├── .gitignore ├── LICENSE ├── README.md ├── api ├── isis │ ├── Makefile │ ├── goisis.pb.go │ └── goisis.proto └── ospf │ ├── Makefile │ ├── goospf.pb.go │ └── goospf.proto ├── cmd ├── goisis │ └── main.go ├── goisisd │ └── main.go ├── goospf │ └── main.go ├── goospfd │ └── main.go ├── gotestconfig │ └── main.go └── gotestpfpkt │ └── main.go ├── docs └── sources │ ├── goisis.md │ ├── images │ ├── srv6-plan_isis-bgpls-srtep.png │ ├── srv6-plan_isis-only.png │ └── srv6-plan_isis-srtep.png │ └── srv6-plan.md ├── internal └── pkg │ ├── isis │ ├── command │ │ ├── command.go │ │ ├── database.go │ │ ├── interface.go │ │ └── route.go │ └── config │ │ ├── config.go │ │ ├── defaults.go │ │ ├── parse.go │ │ ├── structs.go │ │ ├── structs_test.go │ │ └── validate.go │ ├── kernel │ ├── kernel.go │ └── kernel_test.go │ ├── ospf │ ├── command │ │ └── command.go │ └── config │ │ ├── config.go │ │ ├── defaults.go │ │ ├── parse.go │ │ ├── structs.go │ │ ├── structs_test.go │ │ └── validate.go │ └── util │ └── ip.go └── pkg ├── isis ├── packet │ ├── packet.go │ ├── pdu_base.go │ ├── pdu_hello.go │ ├── pdu_hello_test.go │ ├── pdu_linkstate.go │ ├── pdu_linkstate_test.go │ ├── pdu_seqnum.go │ ├── pdu_seqnum_test.go │ ├── tlv_base.go │ ├── tlv_iso10589.go │ ├── tlv_iso10589_test.go │ ├── tlv_rfc1195.go │ ├── tlv_rfc1195_test.go │ ├── tlv_rfc5301.go │ ├── tlv_rfc5301_test.go │ ├── tlv_rfc5303.go │ ├── tlv_rfc5303_test.go │ ├── tlv_rfc5305.go │ ├── tlv_rfc5305_test.go │ ├── tlv_rfc5308.go │ └── tlv_rfc5308_test.go └── server │ ├── adjacency.go │ ├── api.go │ ├── circuit.go │ ├── consts.go │ ├── decision.go │ ├── flags.go │ ├── hello.go │ ├── isis.go │ ├── linkstate.go │ ├── lsdb.go │ ├── periodic.go │ ├── reachability.go │ ├── seqnum.go │ ├── socket.go │ ├── syscall.go │ └── update.go └── ospf ├── packet └── packet.go └── server ├── api.go ├── decision.go ├── ospf.go ├── periodic.go └── update.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoLSR: OSPF/IS-IS implementation in Go 2 | 3 | GoLSR is an open source OSPF/IS-IS implementation implemented in a modern programming language, [the Go Programming Language](http://golang.org/). 4 | 5 | ---- 6 | 7 | GoBGP っぽい OSPF/IS-IS の実装があったら面白いかなー、という思いつきで始めました。 8 | 9 | とりあえず OSPF は置いといて IS-IS を実装しています。 10 | 11 | - [GoISIS: IS-IS implementation in Go](docs/sources/goisis.md) 12 | 13 | -------------------------------------------------------------------------------- /api/isis/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2019-2019 Masakazu Asama. 3 | # Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | # implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | .PHONY: all 19 | 20 | all: goisis.pb.go 21 | 22 | goisis.pb.go: goisis.proto 23 | protoc --go_out=plugins=grpc:. goisis.proto 24 | 25 | -------------------------------------------------------------------------------- /api/isis/goisis.proto: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | syntax = "proto3"; 19 | 20 | //import "google/protobuf/any.proto"; 21 | //import "google/protobuf/empty.proto"; 22 | 23 | package goisisapi; 24 | 25 | service GoisisApi { 26 | rpc Enable(EnableRequest) returns (EnableResponse); 27 | rpc Disable(DisableRequest) returns (DisableResponse); 28 | 29 | rpc InterfaceEnable(InterfaceEnableRequest) returns (InterfaceEnableResponse); 30 | rpc InterfaceDisable(InterfaceDisableRequest) returns (InterfaceDisableResponse); 31 | 32 | rpc AdjacencyGet(AdjacencyGetRequest) returns (AdjacencyGetResponse); 33 | rpc AdjacencyMonitor(AdjacencyMonitorRequest) returns (stream AdjacencyMonitorResponse); 34 | 35 | rpc DbLsGet(DbLsGetRequest) returns (DbLsGetResponse); 36 | rpc DbLsMonitor(DbLsMonitorRequest) returns (stream DbLsMonitorResponse); 37 | 38 | rpc DbRiGet(DbRiGetRequest) returns (DbRiGetResponse); 39 | rpc DbRiMonitor(DbRiMonitorRequest) returns (stream DbRiMonitorResponse); 40 | } 41 | 42 | message EnableRequest { 43 | } 44 | 45 | message EnableResponse { 46 | string result = 1; 47 | } 48 | 49 | message DisableRequest { 50 | } 51 | 52 | message DisableResponse { 53 | string result = 1; 54 | } 55 | 56 | message InterfaceEnableRequest { 57 | string interface = 1; 58 | } 59 | 60 | message InterfaceEnableResponse { 61 | string result = 1; 62 | } 63 | 64 | message InterfaceDisableRequest { 65 | string interface = 1; 66 | } 67 | 68 | message InterfaceDisableResponse { 69 | string result = 1; 70 | } 71 | 72 | message AdjacencyGetRequest { 73 | } 74 | 75 | message AdjacencyGetResponse { 76 | } 77 | 78 | message AdjacencyMonitorRequest { 79 | string interface = 1; 80 | } 81 | 82 | message AdjacencyMonitorResponse { 83 | repeated Adjacency adjacencies = 1; 84 | } 85 | 86 | message DbLsGetRequest { 87 | } 88 | 89 | message DbLsGetResponse { 90 | } 91 | 92 | message DbLsMonitorRequest { 93 | string level = 1; 94 | } 95 | 96 | message DbLsMonitorResponse { 97 | repeated Lsp lsps = 1; 98 | } 99 | 100 | message DbRiGetRequest { 101 | } 102 | 103 | message DbRiGetResponse { 104 | } 105 | 106 | message DbRiMonitorRequest { 107 | string level = 1; 108 | string address_family = 2; 109 | } 110 | 111 | message DbRiMonitorResponse { 112 | repeated Route routes = 1; 113 | } 114 | 115 | // 116 | 117 | message Adjacency { 118 | string interface = 1; 119 | string neighbor_type = 2; 120 | string neighbor_sysid = 3; 121 | uint32 neighbor_extended_circuit_id = 4; 122 | string neighbor_snpa = 5; 123 | string usage = 6; 124 | uint32 hold_timer = 7; 125 | uint32 neighbor_priority = 8; 126 | uint32 lastuptime = 9; 127 | string state = 10; 128 | } 129 | 130 | message Lsp { 131 | string level = 1; 132 | bool decoded_completed = 2; 133 | string raw_data = 3; 134 | string lsp_id = 4; 135 | uint32 checksum = 5; 136 | uint32 remaining_lifetime = 6; 137 | uint32 sequence = 7; 138 | uint32 attributes = 8; 139 | repeated string ipv4_addresses = 9; 140 | repeated string ipv6_addresses = 10; 141 | string ipv4_te_routerid = 11; 142 | string ipv6_te_routerid = 12; 143 | repeated uint32 protocol_supporteds = 13; 144 | string dynamic_hostname = 14; 145 | Authentication authentication = 15; 146 | MtEntries mt_entries = 16; 147 | RouterCapabilities router_capabilities = 17; 148 | NodeTags node_tags = 18; 149 | bytes binary = 19; 150 | } 151 | 152 | message Route { 153 | string level = 1; 154 | string address_family = 2; 155 | string prefix = 3; 156 | repeated NextHop next_hops = 4; 157 | uint32 metric = 5; 158 | } 159 | 160 | message Authentication { 161 | string authentication_type = 1; 162 | string authentication_key = 2; 163 | } 164 | 165 | message Topology { 166 | uint32 mt_id = 1; 167 | uint32 attributes = 2; 168 | } 169 | 170 | message MtEntries { 171 | repeated Topology topologies = 1; 172 | } 173 | 174 | message RouterCapabilities { 175 | uint32 flags = 1; 176 | } 177 | 178 | message NodeTags { 179 | } 180 | 181 | message Global { 182 | string system_id = 1; 183 | } 184 | 185 | message NextHop { 186 | string outgoing_interface = 1; 187 | string next_hop = 2; 188 | } 189 | -------------------------------------------------------------------------------- /api/ospf/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2019-2019 Masakazu Asama. 3 | # Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | # implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | .PHONY: all 19 | 20 | all: goospf.pb.go 21 | 22 | goospf.pb.go: goospf.proto 23 | protoc --go_out=plugins=grpc:. goospf.proto 24 | 25 | -------------------------------------------------------------------------------- /api/ospf/goospf.proto: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | syntax = "proto3"; 19 | 20 | //import "google/protobuf/any.proto"; 21 | //import "google/protobuf/empty.proto"; 22 | 23 | package goospfapi; 24 | 25 | service GoospfApi { 26 | rpc Enable(EnableRequest) returns (EnableResponse); 27 | rpc Disable(DisableRequest) returns (DisableResponse); 28 | } 29 | 30 | message EnableRequest { 31 | } 32 | 33 | message EnableResponse { 34 | string result = 1; 35 | } 36 | 37 | message DisableRequest { 38 | } 39 | 40 | message DisableResponse { 41 | string result = 1; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /cmd/goisis/main.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "os" 23 | 24 | "github.com/m-asama/golsr/internal/pkg/isis/command" 25 | "google.golang.org/grpc" 26 | ) 27 | 28 | var version = "master" 29 | 30 | func main() { 31 | if len(os.Args) > 1 && os.Args[1] == "--version" { 32 | fmt.Println("goisis version", version) 33 | os.Exit(0) 34 | } 35 | grpc.EnableTracing = false 36 | command.NewRootCmd().Execute() 37 | } 38 | -------------------------------------------------------------------------------- /cmd/goisisd/main.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "io/ioutil" 23 | "os" 24 | "os/signal" 25 | "sync" 26 | "syscall" 27 | 28 | "github.com/jessevdk/go-flags" 29 | "github.com/kr/pretty" 30 | log "github.com/sirupsen/logrus" 31 | "golang.org/x/net/context" 32 | "google.golang.org/grpc" 33 | 34 | api "github.com/m-asama/golsr/api/isis" 35 | "github.com/m-asama/golsr/internal/pkg/isis/config" 36 | "github.com/m-asama/golsr/pkg/isis/server" 37 | ) 38 | 39 | var version = "master" 40 | 41 | func main() { 42 | sigCh := make(chan os.Signal, 1) 43 | signal.Notify(sigCh, syscall.SIGTERM) 44 | var opts struct { 45 | ConfigFile string `short:"f" long:"config-file" description:"specifying a config file"` 46 | ConfigType string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"` 47 | LogLevel string `short:"l" long:"log-level" description:"specifying log level"` 48 | LogPlain bool `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"` 49 | UseSyslog string `short:"s" long:"syslog" description:"use syslogd"` 50 | Facility string `long:"syslog-facility" description:"specify syslog facility"` 51 | DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"` 52 | GrpcHosts string `long:"api-hosts" description:"specify the hosts that goisisd listens on" default:":50052"` 53 | Dry bool `short:"d" long:"dry-run" description:"check configuration"` 54 | Version bool `long:"version" description:"show version number"` 55 | } 56 | _, err := flags.Parse(&opts) 57 | if err != nil { 58 | os.Exit(1) 59 | } 60 | 61 | if opts.Version { 62 | fmt.Println("goisisd version", version) 63 | os.Exit(0) 64 | } 65 | 66 | switch opts.LogLevel { 67 | case "debug": 68 | log.SetLevel(log.DebugLevel) 69 | log.SetReportCaller(true) 70 | case "info": 71 | log.SetLevel(log.InfoLevel) 72 | default: 73 | log.SetLevel(log.InfoLevel) 74 | } 75 | 76 | if opts.DisableStdlog { 77 | log.SetOutput(ioutil.Discard) 78 | } else { 79 | log.SetOutput(os.Stdout) 80 | } 81 | 82 | if opts.LogPlain { 83 | if opts.DisableStdlog { 84 | log.SetFormatter(&log.TextFormatter{ 85 | DisableColors: true, 86 | }) 87 | } 88 | } else { 89 | log.SetFormatter(&log.JSONFormatter{}) 90 | } 91 | 92 | if opts.Dry { 93 | configCh := make(chan *config.IsisConfig) 94 | go config.Serve(opts.ConfigFile, opts.ConfigType, configCh) 95 | c := <-configCh 96 | if opts.LogLevel == "debug" { 97 | pretty.Println(c) 98 | } 99 | os.Exit(0) 100 | } 101 | 102 | var wg sync.WaitGroup 103 | 104 | log.Info("goisisd started") 105 | 106 | isisServer := server.NewIsisServer(opts.ConfigFile, opts.ConfigType) 107 | wg.Add(1) 108 | go isisServer.Serve(&wg) 109 | 110 | var grpcOpts []grpc.ServerOption 111 | apiServer := server.NewApiServer(isisServer, grpc.NewServer(grpcOpts...), opts.GrpcHosts) 112 | wg.Add(1) 113 | go apiServer.Serve(&wg) 114 | 115 | <-sigCh 116 | 117 | log.Info("goisisd stoping") 118 | apiServer.Disable(context.Background(), &api.DisableRequest{}) 119 | apiServer.Exit() 120 | isisServer.Exit() 121 | 122 | wg.Wait() 123 | log.Info("goisisd terminated") 124 | } 125 | -------------------------------------------------------------------------------- /cmd/goospf/main.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "os" 23 | 24 | "github.com/m-asama/golsr/internal/pkg/ospf/command" 25 | "google.golang.org/grpc" 26 | ) 27 | 28 | var version = "master" 29 | 30 | func main() { 31 | if len(os.Args) > 1 && os.Args[1] == "--version" { 32 | fmt.Println("goospf version", version) 33 | os.Exit(0) 34 | } 35 | grpc.EnableTracing = false 36 | command.NewRootCmd().Execute() 37 | } 38 | -------------------------------------------------------------------------------- /cmd/goospfd/main.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | "io/ioutil" 23 | "os" 24 | "os/signal" 25 | "sync" 26 | "syscall" 27 | 28 | "github.com/jessevdk/go-flags" 29 | "github.com/kr/pretty" 30 | log "github.com/sirupsen/logrus" 31 | "golang.org/x/net/context" 32 | "google.golang.org/grpc" 33 | 34 | api "github.com/m-asama/golsr/api/ospf" 35 | "github.com/m-asama/golsr/internal/pkg/ospf/config" 36 | "github.com/m-asama/golsr/pkg/ospf/server" 37 | ) 38 | 39 | var version = "master" 40 | 41 | func main() { 42 | sigCh := make(chan os.Signal, 1) 43 | signal.Notify(sigCh, syscall.SIGTERM) 44 | var opts struct { 45 | ConfigFile string `short:"f" long:"config-file" description:"specifying a config file"` 46 | ConfigType string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"` 47 | LogLevel string `short:"l" long:"log-level" description:"specifying log level"` 48 | LogPlain bool `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"` 49 | UseSyslog string `short:"s" long:"syslog" description:"use syslogd"` 50 | Facility string `long:"syslog-facility" description:"specify syslog facility"` 51 | DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"` 52 | GrpcHosts string `long:"api-hosts" description:"specify the hosts that goospfd listens on" default:":50052"` 53 | Dry bool `short:"d" long:"dry-run" description:"check configuration"` 54 | Version bool `long:"version" description:"show version number"` 55 | } 56 | _, err := flags.Parse(&opts) 57 | if err != nil { 58 | os.Exit(1) 59 | } 60 | 61 | if opts.Version { 62 | fmt.Println("goospfd version", version) 63 | os.Exit(0) 64 | } 65 | 66 | switch opts.LogLevel { 67 | case "debug": 68 | log.SetLevel(log.DebugLevel) 69 | log.SetReportCaller(true) 70 | case "info": 71 | log.SetLevel(log.InfoLevel) 72 | default: 73 | log.SetLevel(log.InfoLevel) 74 | } 75 | 76 | if opts.DisableStdlog { 77 | log.SetOutput(ioutil.Discard) 78 | } else { 79 | log.SetOutput(os.Stdout) 80 | } 81 | 82 | if opts.LogPlain { 83 | if opts.DisableStdlog { 84 | log.SetFormatter(&log.TextFormatter{ 85 | DisableColors: true, 86 | }) 87 | } 88 | } else { 89 | log.SetFormatter(&log.JSONFormatter{}) 90 | } 91 | 92 | if opts.Dry { 93 | configCh := make(chan *config.OspfConfig) 94 | go config.Serve(opts.ConfigFile, opts.ConfigType, configCh) 95 | c := <-configCh 96 | if opts.LogLevel == "debug" { 97 | pretty.Println(c) 98 | } 99 | os.Exit(0) 100 | } 101 | 102 | var wg sync.WaitGroup 103 | 104 | log.Info("goospfd started") 105 | 106 | ospfServer := server.NewOspfServer(opts.ConfigFile, opts.ConfigType) 107 | wg.Add(1) 108 | go ospfServer.Serve(&wg) 109 | 110 | var grpcOpts []grpc.ServerOption 111 | apiServer := server.NewApiServer(ospfServer, grpc.NewServer(grpcOpts...), opts.GrpcHosts) 112 | wg.Add(1) 113 | go apiServer.Serve(&wg) 114 | 115 | <-sigCh 116 | 117 | log.Info("goospfd stoping") 118 | apiServer.Disable(context.Background(), &api.DisableRequest{}) 119 | apiServer.Exit() 120 | ospfServer.Exit() 121 | 122 | wg.Wait() 123 | log.Info("goospfd terminated") 124 | } 125 | -------------------------------------------------------------------------------- /cmd/gotestconfig/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/m-asama/golsr/internal/pkg/isis/config" 6 | ) 7 | 8 | func main() { 9 | fmt.Println("MAIN") 10 | configCh := make(chan *config.IsisConfig) 11 | go config.ReadConfigfileServe("test.toml", "toml", configCh) 12 | c := <-configCh 13 | if c.Config.Enable != nil { 14 | fmt.Println(*c.Config.Enable) 15 | } 16 | if c.Config.LevelType != nil { 17 | fmt.Println(*c.Config.LevelType) 18 | } 19 | if c.Authentication.Config.Key != nil { 20 | fmt.Println("c.Authentication.Config.Key", *c.Authentication.Config.Key) 21 | } 22 | if c.Authentication.Level1.Config.Key != nil { 23 | fmt.Println("c.Authentication.Level1.Config.Key", *c.Authentication.Level1.Config.Key) 24 | } 25 | for i, v := range c.Config.AreaAddress { 26 | fmt.Print(i) 27 | fmt.Print(" : ") 28 | fmt.Print(v) 29 | fmt.Println("") 30 | } 31 | for i, v := range c.Interfaces { 32 | fmt.Print(i) 33 | fmt.Print(" : ") 34 | if v.Config.Name != nil { 35 | fmt.Print(*v.Config.Name) 36 | } 37 | fmt.Println("") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /cmd/gotestpfpkt/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "github.com/m-asama/golsr/pkg/isis/server" 7 | "net" 8 | "os" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | func handler(fd int) { 14 | // func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) 15 | 16 | fmt.Println("handler...") 17 | buf := make([]byte, 8192) 18 | for { 19 | fmt.Println("x") 20 | n, from, err := syscall.Recvfrom(fd, buf, 0) 21 | fmt.Println("Recvfrom:") 22 | fmt.Println(n, from, err) 23 | for i := 0; i < 10; i++ { 24 | fmt.Printf("%02x ", buf[i]) 25 | } 26 | fmt.Println("") 27 | } 28 | } 29 | 30 | func htons(i uint16) uint16 { 31 | b := make([]byte, 2) 32 | binary.BigEndian.PutUint16(b, i) 33 | return *(*uint16)(unsafe.Pointer(&b[0])) 34 | } 35 | 36 | func main() { 37 | 38 | if len(os.Args) != 2 { 39 | os.Exit(1) 40 | } 41 | ifname := os.Args[1] 42 | 43 | fmt.Println("=============================================================================") 44 | fmt.Println("= Start sending =") 45 | fmt.Println("=============================================================================") 46 | 47 | /* 48 | pkt := []byte{ 49 | 0x6c, 0x62, 0x6d, 0x50, 0xe6, 0xe4, 0x94, 0xde, 0x80, 0xa5, 0xec, 0x79, 0x08, 0x00, 0x45, 0x00, 50 | 0x00, 0x3c, 0x4b, 0x72, 0x40, 0x00, 0x40, 0x06, 0x44, 0x7d, 0xc0, 0xa8, 0x34, 0x7b, 0xd8, 0x3a, 51 | 0xdd, 0x6e, 0xa6, 0x37, 0x01, 0xbb, 0x32, 0xf3, 0x21, 0xa9, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 52 | 0x72, 0x10, 0xae, 0xa5, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0x15, 0x13, 53 | 0x6a, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07, 54 | } 55 | */ 56 | pkt := []byte{ 57 | 0xfe, 0xfe, 0x03, 0x83, 0x1b, 0x01, 0x00, 0x14, 0x01, 0x00, /* ........ */ 58 | 0x00, 0x00, 0x63, 0x04, 0x8d, 0x36, 0xd3, 0x64, /* ..c..6.d */ 59 | 0x2f, 0x27, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, /* /'...... */ 60 | 0x02, 0xa2, 0xbe, 0x03, 0x81, 0x02, 0xcc, 0x8e, /* ........ */ 61 | 0x01, 0x02, 0x01, 0x01, 0x89, 0x08, 0x66, 0x72, /* ......fr */ 62 | 0x72, 0x74, 0x65, 0x73, 0x74, 0x31, 0x86, 0x04, /* rtest1.. */ 63 | 0xc0, 0xa8, 0x01, 0x01, 0x84, 0x04, 0xc0, 0xa8, /* ........ */ 64 | 0x01, 0x01, 0x87, 0x18, 0x00, 0x00, 0x00, 0x0a, /* ........ */ 65 | 0x18, 0xc0, 0xa8, 0x0c, 0x00, 0x00, 0x00, 0x0a, /* ........ */ 66 | 0x18, 0xc0, 0xa8, 0x0d, 0x00, 0x00, 0x00, 0x0a, /* ........ */ 67 | 0x18, 0xc0, 0xa8, 0x01, 0xec, 0x0e, 0x00, 0x00, /* ........ */ 68 | 0x00, 0x0a, 0x00, 0x40, 0x20, 0x01, 0x0d, 0xb8, /* ...@ ... */ 69 | 0x00, 0x00, 0x00, 0x01, 70 | } 71 | 72 | //fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, syscall.ETH_P_ALL) 73 | fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, int(htons(uint16(syscall.ETH_P_ALL)))) 74 | if err != nil { 75 | fmt.Println("=============================================================================") 76 | fmt.Println("= Error 1 =") 77 | fmt.Println("=============================================================================") 78 | fmt.Println(err) 79 | } 80 | 81 | filter := make([]server.SockFilter, 6) 82 | filter[0] = server.SockFilter{0x28, 0, 0, 0x0000000e - 14} 83 | filter[1] = server.SockFilter{0x15, 0, 3, 0x0000fefe} 84 | filter[2] = server.SockFilter{0x30, 0, 0, 0x00000011 - 14} 85 | filter[3] = server.SockFilter{0x15, 0, 1, 0x00000083} 86 | filter[4] = server.SockFilter{0x6, 0, 0, 0x00040000} 87 | filter[5] = server.SockFilter{0x6, 0, 0, 0x00000000} 88 | bpf := server.SockFprog{ 89 | Len: 6, 90 | Filter: (*server.SockFilter)(unsafe.Pointer(&filter[0])), 91 | } 92 | server.SetsockoptAttachFilter(fd, syscall.SOL_SOCKET, syscall.SO_ATTACH_FILTER, &bpf) 93 | if err != nil { 94 | fmt.Println("=============================================================================") 95 | fmt.Println("= Error x =") 96 | fmt.Println("=============================================================================") 97 | fmt.Println(err) 98 | } 99 | 100 | if_info, err := net.InterfaceByName(ifname) 101 | if err != nil { 102 | fmt.Println("=============================================================================") 103 | fmt.Println("= Error 2 =") 104 | fmt.Println("=============================================================================") 105 | fmt.Println(err) 106 | } 107 | 108 | addr := syscall.SockaddrLinklayer{ 109 | Protocol: syscall.ETH_P_ALL, 110 | Ifindex: if_info.Index, 111 | } 112 | addr.Protocol = htons(uint16(syscall.ETH_P_ALL)) 113 | err = syscall.Bind(fd, &addr) 114 | 115 | /* 116 | copy(pkt[6:12], if_info.HardwareAddr[0:6]) 117 | fmt.Println(len(if_info.HardwareAddr)) 118 | 119 | var haddr [8]byte 120 | copy(haddr[0:7], if_info.HardwareAddr[0:7]) 121 | addr := syscall.SockaddrLinklayer{ 122 | Protocol: syscall.ETH_P_IP, 123 | Ifindex: if_info.Index, 124 | Halen: uint8(len(if_info.HardwareAddr)), 125 | Addr: haddr, 126 | } 127 | */ 128 | 129 | AllL1ISS := []byte{0x01, 0x80, 0xC2, 0x00, 0x00, 0x14} 130 | // AllL2ISS := []byte{0x01, 0x80, 0xC2, 0x00, 0x00, 0x15} 131 | // AllISS := []byte{0x09, 0x00, 0x2B, 0x00, 0x00, 0x05} 132 | 133 | mreq := server.PacketMreq{ 134 | Ifindex: int32(if_info.Index), 135 | Type: syscall.PACKET_MR_MULTICAST, 136 | ALen: uint16(len(if_info.HardwareAddr)), 137 | } 138 | copy(mreq.Address[0:6], AllL1ISS[0:6]) 139 | mreq.Address[6] = 0x0 140 | mreq.Address[7] = 0x0 141 | /* 142 | mreq := server.PacketMreq{ 143 | Ifindex: int32(if_info.Index), 144 | Type: syscall.PACKET_MR_PROMISC, 145 | } 146 | */ 147 | 148 | err = server.SetsockoptPacketMreq(fd, syscall.SOL_PACKET, syscall.PACKET_ADD_MEMBERSHIP, &mreq) 149 | if err != nil { 150 | fmt.Println("=============================================================================") 151 | fmt.Println("= Error x =") 152 | fmt.Println("=============================================================================") 153 | fmt.Println(err) 154 | } 155 | 156 | var dad [8]byte 157 | copy(dad[0:6], []byte{0x01, 0x80, 0xC2, 0x00, 0x00, 0x14}[0:6]) 158 | dad[6] = 0x0 159 | dad[7] = 0x0 160 | dstaddr := syscall.SockaddrLinklayer{ 161 | Protocol: syscall.ETH_P_IP, 162 | Ifindex: if_info.Index, 163 | Halen: uint8(len(if_info.HardwareAddr)), 164 | Addr: dad, 165 | } 166 | err = syscall.Sendto(fd, pkt, 0, &dstaddr) 167 | if err != nil { 168 | fmt.Println("=============================================================================") 169 | fmt.Println("= Error 5 =") 170 | fmt.Println("=============================================================================") 171 | fmt.Println(err) 172 | } else { 173 | fmt.Println("=============================================================================") 174 | fmt.Println("= Packet is sent =") 175 | fmt.Println("=============================================================================") 176 | } 177 | handler(fd) 178 | 179 | } 180 | -------------------------------------------------------------------------------- /docs/sources/goisis.md: -------------------------------------------------------------------------------- 1 | # GoISIS: IS-IS implementation in Go 2 | 3 | ## これは何? 4 | 5 | Go 言語で書かれた IS-IS 実装です。 6 | 7 | まだ経路情報を FIB に入れる仕組みを用意していないのでトポロジー情報を収集して計算結果の経路を表示するくらいしかできません。 8 | 9 | あと L2 のアタッチビットの処理とかエクスターナルの扱いをちゃんとしてません。 10 | 11 | 認証もまだ実装してません。 12 | 13 | 全体的にまだ書きなぐった状態なのでこれから徐々に綺麗にしていきたい所存。 14 | 15 | 最終的には SRv6 SID TLV に対応して TI-LFA に対応したり GoBGP と連携して BGP-LS 対応とかしたい。 16 | 17 | ## 使い方 18 | 19 | まず go get コマンドで goisisd(デーモン) と goisis(goisisd とやりとりするコマンド) をコンパイルします。 20 | 21 | ``` 22 | $ go get github.com/m-asama/golsr/cmd/goisis 23 | $ go get github.com/m-asama/golsr/cmd/goisisd 24 | ``` 25 | 26 | 次に以下のような goisisd の設定ファイル goisisd.toml を作ります。 27 | 28 | ``` 29 | [config] 30 | system-id = "4a6f.ee64.a2c0" 31 | area-address-list = ["01", "02"] 32 | 33 | [[interfaces]] 34 | [interfaces.config] 35 | name = "lo" 36 | 37 | [[interfaces]] 38 | [interfaces.config] 39 | name = "eth12" 40 | #interface-type = "point-to-point" 41 | [interfaces.priority.config] 42 | value = 70 43 | 44 | [[interfaces]] 45 | [interfaces.config] 46 | name = "eth13" 47 | #interface-type = "point-to-point" 48 | [interfaces.priority.config] 49 | value = 70 50 | ``` 51 | 52 | そして goisisd を実行します。 53 | 54 | ``` 55 | $ sudo goisisd -f ./goisisd.toml 56 | ``` 57 | 58 | 隣接一覧を表示するには以下のコマンドを実行します。 59 | 60 | ``` 61 | $ sudo goisis interface adjacency 62 | Interface : eth12 63 | NeighborType : ADJ_TYPE_LEVEL1_LAN 64 | NeighborSysid : faa56cc9adad 65 | NeighborExtendedCircuitId : 0 66 | NeighborSnpa : 2e08db03b646 67 | Usage : ADJ_USAGE_LEVEL1 68 | HoldTimer : 97 69 | NeighborPriority : 64 70 | Lastuptime : %!s(uint32=0) 71 | State : ADJ_3WAY_STATE_UP 72 | 73 | Interface : eth12 74 | NeighborType : ADJ_TYPE_LEVEL2_LAN 75 | NeighborSysid : faa56cc9adad 76 | NeighborExtendedCircuitId : 0 77 | NeighborSnpa : 2e08db03b646 78 | Usage : ADJ_USAGE_LEVEL2 79 | HoldTimer : 97 80 | NeighborPriority : 64 81 | Lastuptime : %!s(uint32=0) 82 | State : ADJ_3WAY_STATE_UP 83 | 84 | ... 中略 ... 85 | ``` 86 | 87 | LSDB 一覧を表示するには以下のコマンドを実行します。 88 | 89 | ``` 90 | $ sudo goisis database linkstate all 91 | Level : L1 92 | LspId : 4a6fee64a2c00000 93 | Checksum : 0x9eaf 94 | RemainingLifetime : 67 95 | Sequence : 0x0004(4) 96 | Ipv4Addresses : [] 97 | Ipv6Addresses : [] 98 | Ipv4TeRouterid : 99 | Ipv6TeRouterid : 100 | ProtocolSupported : [] 101 | DynamicHostname : 102 | 103 | Level : L1 104 | LspId : 4a6fee64a2c00300 105 | Checksum : 0x21fa 106 | RemainingLifetime : 67 107 | Sequence : 0x0004(4) 108 | Ipv4Addresses : [] 109 | Ipv6Addresses : [] 110 | Ipv4TeRouterid : 111 | Ipv6TeRouterid : 112 | ProtocolSupported : [] 113 | DynamicHostname : 114 | 115 | ... 中略 ... 116 | ``` 117 | 118 | 経路情報を表示するには以下のコマンドを実行します。 119 | 120 | ``` 121 | $ sudo goisis route all all 122 | LV PREFIX DIST I/F NEXTHOP 123 | L1 192.168.2.0/24 20 eth12 192.168.12.2 124 | L2 192.168.2.0/24 20 eth12 192.168.12.2 125 | L1 192.168.3.0/24 20 eth13 192.168.13.3 126 | L2 192.168.3.0/24 20 eth13 192.168.13.3 127 | L1 192.168.4.0/24 30 eth13 192.168.13.3 128 | eth12 192.168.12.2 129 | L2 192.168.4.0/24 30 eth13 192.168.13.3 130 | eth12 192.168.12.2 131 | L1 2001:db8:0:2::/64 20 eth12 fe80::2c08:dbff:fe03:b646 132 | L2 2001:db8:0:2::/64 20 eth12 fe80::2c08:dbff:fe03:b646 133 | L1 2001:db8:0:3::/64 20 eth13 fe80::d869:acff:feab:731 134 | L2 2001:db8:0:3::/64 20 eth13 fe80::d869:acff:feab:731 135 | L1 2001:db8:0:4::/64 30 eth13 fe80::d869:acff:feab:731 136 | eth12 fe80::2c08:dbff:fe03:b646 137 | L2 2001:db8:0:4::/64 30 eth13 fe80::d869:acff:feab:731 138 | eth12 fe80::2c08:dbff:fe03:b646 139 | ``` 140 | -------------------------------------------------------------------------------- /docs/sources/images/srv6-plan_isis-bgpls-srtep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-asama/golsr/246b71681ecfe69d88c56ec3efa92bba90409add/docs/sources/images/srv6-plan_isis-bgpls-srtep.png -------------------------------------------------------------------------------- /docs/sources/images/srv6-plan_isis-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-asama/golsr/246b71681ecfe69d88c56ec3efa92bba90409add/docs/sources/images/srv6-plan_isis-only.png -------------------------------------------------------------------------------- /docs/sources/images/srv6-plan_isis-srtep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-asama/golsr/246b71681ecfe69d88c56ec3efa92bba90409add/docs/sources/images/srv6-plan_isis-srtep.png -------------------------------------------------------------------------------- /docs/sources/srv6-plan.md: -------------------------------------------------------------------------------- 1 | # SRv6 計画 2 | 3 | ## goisisd 設定ファイルイメージ 4 | 5 | https://tools.ietf.org/html/draft-ietf-isis-yang-isis-cfg 6 | 7 | ``` 8 | [config] 9 | enable = true 10 | level-type = "level-1" 11 | system-id = "36d3.642f.27ad" 12 | area-address = ["01"] 13 | [authentication.config] 14 | key = "hogehoge" 15 | crypto-algorithm = "md5" 16 | [authentication.level-1.config] 17 | key = "piyopiyo" 18 | crypto-algorithm = "md5" 19 | 20 | [[interfaces]] 21 | [interfaces.config] 22 | name = "eth0" 23 | 24 | [[interfaces]] 25 | [interfaces.config] 26 | name = "eth1" 27 | ``` 28 | 29 | ## 構成例 30 | 31 | ### IS-IS のみ構成 32 | ![IS-IS のみ構成](./images/srv6-plan_isis-only.png) 33 | 34 | ### IS-IS + コントローラ構成 35 | ![IS-IS + コントローラ構成](./images/srv6-plan_isis-srtep.png) 36 | 37 | ### IS-IS + BGP-LS + コントローラ構成 38 | ![IS-IS + BGP-LS + コントローラ構成](./images/srv6-plan_isis-bgpls-srtep.png) 39 | -------------------------------------------------------------------------------- /internal/pkg/isis/command/command.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package command 19 | 20 | import ( 21 | "context" 22 | "encoding/json" 23 | "fmt" 24 | "net" 25 | "os" 26 | "strconv" 27 | "time" 28 | 29 | "github.com/spf13/cobra" 30 | "google.golang.org/grpc" 31 | 32 | api "github.com/m-asama/golsr/api/isis" 33 | ) 34 | 35 | var globalOpts struct { 36 | Host string 37 | Port int 38 | Debug bool 39 | Quiet bool 40 | Json bool 41 | GenCmpl bool 42 | BashCmplFile string 43 | } 44 | 45 | var client api.GoisisApiClient 46 | var ctx context.Context 47 | 48 | func printError(err error) { 49 | if globalOpts.Json { 50 | j, _ := json.Marshal(struct { 51 | Error string `json:"error"` 52 | }{Error: err.Error()}) 53 | fmt.Println(string(j)) 54 | } else { 55 | fmt.Println(err) 56 | } 57 | } 58 | 59 | func exitWithError(err error) { 60 | printError(err) 61 | os.Exit(1) 62 | } 63 | 64 | func newClient(ctx context.Context) (api.GoisisApiClient, error) { 65 | grpcOpts := []grpc.DialOption{grpc.WithTimeout(time.Second), grpc.WithBlock()} 66 | grpcOpts = append(grpcOpts, grpc.WithInsecure()) 67 | 68 | target := net.JoinHostPort(globalOpts.Host, strconv.Itoa(globalOpts.Port)) 69 | if target == "" { 70 | target = ":50052" 71 | } 72 | 73 | conn, err := grpc.DialContext(ctx, target, grpcOpts...) 74 | if err != nil { 75 | return nil, err 76 | } 77 | return api.NewGoisisApiClient(conn), nil 78 | } 79 | 80 | func NewRootCmd() *cobra.Command { 81 | cobra.EnablePrefixMatching = true 82 | rootCmd := &cobra.Command{ 83 | Use: "goisis", 84 | PersistentPreRun: func(cmd *cobra.Command, args []string) { 85 | if !globalOpts.GenCmpl { 86 | var err error 87 | ctx = context.Background() 88 | client, err = newClient(ctx) 89 | if err != nil { 90 | exitWithError(err) 91 | } 92 | } 93 | }, 94 | Run: func(cmd *cobra.Command, args []string) { 95 | if globalOpts.GenCmpl { 96 | cmd.GenBashCompletionFile(globalOpts.BashCmplFile) 97 | } else { 98 | cmd.HelpFunc()(cmd, args) 99 | } 100 | }, 101 | PersistentPostRun: func(cmd *cobra.Command, args []string) { 102 | }, 103 | } 104 | 105 | rootCmd.PersistentFlags().StringVarP(&globalOpts.Host, "host", "u", "127.0.0.1", "host") 106 | rootCmd.PersistentFlags().IntVarP(&globalOpts.Port, "port", "p", 50052, "port") 107 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Json, "json", "j", false, "use json format to output format") 108 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Debug, "debug", "d", false, "use debug") 109 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Quiet, "quiet", "q", false, "use quiet") 110 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.GenCmpl, "gen-cmpl", "c", false, "generate completion file") 111 | rootCmd.PersistentFlags().StringVarP(&globalOpts.BashCmplFile, "bash-cmpl-file", "", "goisis-completion.bash", 112 | "bash cmpl filename") 113 | 114 | enableCmd := &cobra.Command{ 115 | Use: "enable", 116 | Run: func(cmd *cobra.Command, args []string) { 117 | response, _ := client.Enable(ctx, &api.EnableRequest{}) 118 | fmt.Println(response.Result) 119 | }, 120 | } 121 | rootCmd.AddCommand(enableCmd) 122 | 123 | disableCmd := &cobra.Command{ 124 | Use: "disable", 125 | Run: func(cmd *cobra.Command, args []string) { 126 | response, _ := client.Disable(ctx, &api.DisableRequest{}) 127 | fmt.Println(response.Result) 128 | }, 129 | } 130 | rootCmd.AddCommand(disableCmd) 131 | 132 | interfaceCmd := NewInterfaceCmd() 133 | rootCmd.AddCommand(interfaceCmd) 134 | 135 | databaseCmd := NewDatabaseCmd() 136 | rootCmd.AddCommand(databaseCmd) 137 | 138 | routeCmd := NewRouteCmd() 139 | rootCmd.AddCommand(routeCmd) 140 | 141 | return rootCmd 142 | } 143 | -------------------------------------------------------------------------------- /internal/pkg/isis/command/database.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package command 19 | 20 | import ( 21 | "fmt" 22 | "io" 23 | 24 | "github.com/spf13/cobra" 25 | 26 | api "github.com/m-asama/golsr/api/isis" 27 | ) 28 | 29 | func printLsp(lsp *api.Lsp) { 30 | fmt.Printf("Level : %s\n", lsp.Level) 31 | fmt.Printf("LspId : %s\n", lsp.LspId) 32 | fmt.Printf("Checksum : 0x%04x\n", lsp.Checksum) 33 | fmt.Printf("RemainingLifetime : %d\n", lsp.RemainingLifetime) 34 | fmt.Printf("Sequence : 0x%04x(%d)\n", lsp.Sequence, lsp.Sequence) 35 | fmt.Printf("Ipv4Addresses : %s\n", lsp.Ipv4Addresses) 36 | fmt.Printf("Ipv6Addresses : %s\n", lsp.Ipv6Addresses) 37 | fmt.Printf("Ipv4TeRouterid : %s\n", lsp.Ipv4TeRouterid) 38 | fmt.Printf("Ipv6TeRouterid : %s\n", lsp.Ipv6TeRouterid) 39 | fmt.Printf("ProtocolSupported : %s\n", lsp.ProtocolSupporteds) 40 | fmt.Printf("DynamicHostname : %s\n", lsp.DynamicHostname) 41 | fmt.Printf("\n") 42 | } 43 | 44 | func NewDbLinkstateCmd() *cobra.Command { 45 | dbLinkstateCmd := &cobra.Command{ 46 | Use: "linkstate", 47 | Run: func(cmd *cobra.Command, args []string) { 48 | if len(args) != 1 { 49 | return 50 | } 51 | stream, _ := client.DbLsMonitor(ctx, &api.DbLsMonitorRequest{ 52 | Level: args[0], 53 | }) 54 | for { 55 | r, err := stream.Recv() 56 | if err == io.EOF { 57 | break 58 | } else if err != nil { 59 | return 60 | } 61 | for _, lsp := range r.Lsps { 62 | printLsp(lsp) 63 | } 64 | } 65 | }, 66 | } 67 | return dbLinkstateCmd 68 | } 69 | 70 | func NewDatabaseCmd() *cobra.Command { 71 | databaseCmd := &cobra.Command{ 72 | Use: "database", 73 | Run: func(cmd *cobra.Command, args []string) { 74 | }, 75 | } 76 | 77 | dbLinkstateCmd := NewDbLinkstateCmd() 78 | databaseCmd.AddCommand(dbLinkstateCmd) 79 | 80 | return databaseCmd 81 | } 82 | -------------------------------------------------------------------------------- /internal/pkg/isis/command/interface.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package command 19 | 20 | import ( 21 | "fmt" 22 | "io" 23 | 24 | "github.com/spf13/cobra" 25 | 26 | api "github.com/m-asama/golsr/api/isis" 27 | ) 28 | 29 | func printAdjacency(adj *api.Adjacency) { 30 | fmt.Printf("Interface : %s\n", adj.Interface) 31 | fmt.Printf("NeighborType : %s\n", adj.NeighborType) 32 | fmt.Printf("NeighborSysid : %s\n", adj.NeighborSysid) 33 | fmt.Printf("NeighborExtendedCircuitId : %d\n", adj.NeighborExtendedCircuitId) 34 | fmt.Printf("NeighborSnpa : %s\n", adj.NeighborSnpa) 35 | fmt.Printf("Usage : %s\n", adj.Usage) 36 | fmt.Printf("HoldTimer : %d\n", adj.HoldTimer) 37 | fmt.Printf("NeighborPriority : %d\n", adj.NeighborPriority) 38 | fmt.Printf("Lastuptime : %s\n", adj.Lastuptime) 39 | fmt.Printf("State : %s\n", adj.State) 40 | fmt.Printf("\n") 41 | } 42 | 43 | func NewIfEnableCmd() *cobra.Command { 44 | ifEnableCmd := &cobra.Command{ 45 | Use: "enable", 46 | Run: func(cmd *cobra.Command, args []string) { 47 | if len(args) != 1 { 48 | return 49 | } 50 | request := &api.InterfaceEnableRequest{Interface: args[0]} 51 | response, _ := client.InterfaceEnable(ctx, request) 52 | fmt.Println(response.Result) 53 | }, 54 | } 55 | return ifEnableCmd 56 | } 57 | 58 | func NewIfDisableCmd() *cobra.Command { 59 | ifDisableCmd := &cobra.Command{ 60 | Use: "disable", 61 | Run: func(cmd *cobra.Command, args []string) { 62 | if len(args) != 1 { 63 | return 64 | } 65 | request := &api.InterfaceDisableRequest{Interface: args[0]} 66 | response, _ := client.InterfaceDisable(ctx, request) 67 | fmt.Println(response.Result) 68 | }, 69 | } 70 | return ifDisableCmd 71 | } 72 | 73 | func NewIfAdjacencyCmd() *cobra.Command { 74 | ifAdjacencyCmd := &cobra.Command{ 75 | Use: "adjacency", 76 | Run: func(cmd *cobra.Command, args []string) { 77 | ifname := "all" 78 | if len(args) > 0 { 79 | ifname = args[0] 80 | } 81 | stream, _ := client.AdjacencyMonitor(ctx, &api.AdjacencyMonitorRequest{ 82 | Interface: ifname, 83 | }) 84 | for { 85 | r, err := stream.Recv() 86 | if err == io.EOF { 87 | break 88 | } else if err != nil { 89 | return 90 | } 91 | for _, adj := range r.Adjacencies { 92 | printAdjacency(adj) 93 | } 94 | } 95 | }, 96 | } 97 | return ifAdjacencyCmd 98 | } 99 | 100 | func NewInterfaceCmd() *cobra.Command { 101 | interfaceCmd := &cobra.Command{ 102 | Use: "interface", 103 | Run: func(cmd *cobra.Command, args []string) { 104 | }, 105 | } 106 | 107 | ifEnableCmd := NewIfEnableCmd() 108 | interfaceCmd.AddCommand(ifEnableCmd) 109 | 110 | ifDisableCmd := NewIfDisableCmd() 111 | interfaceCmd.AddCommand(ifDisableCmd) 112 | 113 | ifAdjacencyCmd := NewIfAdjacencyCmd() 114 | interfaceCmd.AddCommand(ifAdjacencyCmd) 115 | 116 | return interfaceCmd 117 | } 118 | -------------------------------------------------------------------------------- /internal/pkg/isis/command/route.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package command 19 | 20 | import ( 21 | "fmt" 22 | "io" 23 | 24 | "github.com/spf13/cobra" 25 | 26 | api "github.com/m-asama/golsr/api/isis" 27 | ) 28 | 29 | func printRoute(route *api.Route) { 30 | //fmt.Printf("Level : %s\n", route.Level) 31 | switch route.Level { 32 | case "level-1": 33 | fmt.Printf("L1 ") 34 | case "level-2": 35 | fmt.Printf("L2 ") 36 | default: 37 | fmt.Printf("L? ") 38 | } 39 | fmt.Printf("%-30s ", route.Prefix) 40 | fmt.Printf("%5d ", route.Metric) 41 | first := true 42 | for _, nh := range route.NextHops { 43 | if !first { 44 | fmt.Printf(" ") 45 | } 46 | fmt.Printf("%-8s %-30s\n", nh.OutgoingInterface, nh.NextHop) 47 | if first { 48 | first = false 49 | } 50 | } 51 | } 52 | 53 | func NewRouteCmd() *cobra.Command { 54 | routeCmd := &cobra.Command{ 55 | Use: "route", 56 | Run: func(cmd *cobra.Command, args []string) { 57 | if len(args) != 2 { 58 | return 59 | } 60 | stream, _ := client.DbRiMonitor(ctx, &api.DbRiMonitorRequest{ 61 | Level: args[0], 62 | AddressFamily: args[1], 63 | }) 64 | fmt.Printf("LV %-30s %5s %-8s %-30s\n", "PREFIX", "DIST", "I/F", "NEXTHOP") 65 | for { 66 | r, err := stream.Recv() 67 | if err == io.EOF { 68 | break 69 | } else if err != nil { 70 | return 71 | } 72 | for _, route := range r.Routes { 73 | printRoute(route) 74 | } 75 | } 76 | }, 77 | } 78 | 79 | return routeCmd 80 | } 81 | -------------------------------------------------------------------------------- /internal/pkg/isis/config/config.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import ( 21 | log "github.com/sirupsen/logrus" 22 | "github.com/spf13/viper" 23 | "os" 24 | "os/signal" 25 | "path/filepath" 26 | "syscall" 27 | //yaml "gopkg.in/yaml.v2" 28 | ) 29 | 30 | func detectConfigFileType(path, def string) string { 31 | switch ext := filepath.Ext(path); ext { 32 | case ".toml": 33 | return "toml" 34 | case ".yaml", ".yml": 35 | return "yaml" 36 | case ".json": 37 | return "json" 38 | default: 39 | return def 40 | } 41 | } 42 | 43 | func Serve(path, format string, configCh chan *IsisConfig) { 44 | 45 | //log.Info("ReadConfigfileServe started") 46 | 47 | sigCh := make(chan os.Signal, 1) 48 | signal.Notify(sigCh, syscall.SIGHUP) 49 | 50 | // Update config file type, if detectable 51 | format = detectConfigFileType(path, format) 52 | 53 | cnt := 0 54 | for { 55 | c := &IsisConfig{} 56 | v := viper.New() 57 | v.SetConfigFile(path) 58 | v.SetConfigType(format) 59 | var err error 60 | if err = v.ReadInConfig(); err != nil { 61 | goto ERROR 62 | } 63 | if err = v.UnmarshalExact(c); err != nil { 64 | goto ERROR 65 | } 66 | c.fillDefaults() 67 | if err = c.validate(); err != nil { 68 | goto ERROR 69 | } 70 | if cnt == 0 { 71 | log.WithFields(log.Fields{ 72 | "Topic": "Config", 73 | }).Info("Finished reading the config file") 74 | } 75 | /* 76 | if err = v.WriteConfigAs("/tmp/goisisd.toml"); err != nil { 77 | log.Info("WriteConfigAs failed", err) 78 | } else { 79 | log.Info("WriteConfigAs success") 80 | } 81 | bs, err = yaml.Marshal(c) 82 | if err != nil { 83 | log.Info("yaml.Marshal error") 84 | } else { 85 | fmt.Printf("\n%s", string(bs)) 86 | } 87 | */ 88 | 89 | cnt++ 90 | configCh <- c 91 | goto NEXT 92 | ERROR: 93 | if cnt == 0 { 94 | log.WithFields(log.Fields{ 95 | "Topic": "Config", 96 | "Error": err, 97 | }).Fatalf("Can't read config file %s", path) 98 | } else { 99 | log.WithFields(log.Fields{ 100 | "Topic": "Config", 101 | "Error": err, 102 | }).Warningf("Can't read config file %s", path) 103 | } 104 | NEXT: 105 | <-sigCh 106 | log.WithFields(log.Fields{ 107 | "Topic": "Config", 108 | }).Info("Reload the config file") 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /internal/pkg/isis/config/defaults.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import ( 21 | "github.com/m-asama/golsr/internal/pkg/kernel" 22 | ) 23 | 24 | func (config *Interface) InterfaceAddressFamiliesDefaults(isisConfig *IsisConfig) { 25 | } 26 | 27 | func (config *IsisConfig) AddressFamiliesDefaults() { 28 | var ipv4 *bool 29 | var ipv6 *bool 30 | for _, af := range config.AddressFamilies { 31 | if *af.Config.AddressFamily == "ipv4" { 32 | if af.Config.Enable == nil { 33 | enable := true 34 | af.Config.Enable = &enable 35 | } 36 | ipv4 = af.Config.Enable 37 | } 38 | if *af.Config.AddressFamily == "ipv6" { 39 | if af.Config.Enable == nil { 40 | enable := true 41 | af.Config.Enable = &enable 42 | } 43 | ipv6 = af.Config.Enable 44 | } 45 | } 46 | if ipv4 == nil { 47 | afstr := "ipv4" 48 | enable := true 49 | af := &AddressFamily{ 50 | Config: AddressFamilyConfig{ 51 | AddressFamily: &afstr, 52 | Enable: &enable, 53 | }, 54 | } 55 | config.AddressFamilies = append(config.AddressFamilies, af) 56 | } 57 | if ipv6 == nil { 58 | afstr := "ipv6" 59 | enable := true 60 | af := &AddressFamily{ 61 | Config: AddressFamilyConfig{ 62 | AddressFamily: &afstr, 63 | Enable: &enable, 64 | }, 65 | } 66 | config.AddressFamilies = append(config.AddressFamilies, af) 67 | } 68 | } 69 | 70 | func (config *NodeTag) fillDefaults() { 71 | } 72 | 73 | func (config *AddressFamily) fillDefaults() { 74 | } 75 | 76 | func (config *Topology) fillDefaults() { 77 | for _, nodeTag := range config.NodeTags { 78 | nodeTag.fillDefaults() 79 | } 80 | } 81 | 82 | func (config *InterfaceAddressFamily) fillDefaults() { 83 | } 84 | 85 | func (config *InterfaceTopology) fillDefaults() { 86 | } 87 | 88 | func (config *Interface) fillDefaults(isisConfig *IsisConfig) { 89 | ifaceType := kernel.IfType(0) 90 | if config.Config.Name != nil { 91 | ifaceType = kernel.IfaceType(*config.Config.Name) 92 | } 93 | // name 94 | // level-type 95 | if config.Config.LevelType == nil { 96 | levelType := "level-all" 97 | config.Config.LevelType = &levelType 98 | } 99 | // lsp-pacing-interval 100 | if config.Config.LspPacingInterval == nil { 101 | lspPacingInterval := uint32(33) 102 | config.Config.LspPacingInterval = &lspPacingInterval 103 | } 104 | // lsp-retransmit-interval 105 | if config.Config.LspRetransmitInterval == nil { 106 | lspRetransmitInterval := uint16(5) 107 | config.Config.LspRetransmitInterval = &lspRetransmitInterval 108 | } 109 | // passive 110 | if config.Config.Passive == nil { 111 | passive := false 112 | if ifaceType == kernel.IF_TYPE_LOOPBACK { 113 | passive = true 114 | } 115 | config.Config.Passive = &passive 116 | } 117 | // csnp-interval 118 | if config.Config.CsnpInterval == nil { 119 | csnpInterval := uint16(10) 120 | config.Config.CsnpInterval = &csnpInterval 121 | } 122 | // hello-padding 123 | if config.HelloPadding.Config.Enable == nil { 124 | enable := true 125 | config.HelloPadding.Config.Enable = &enable 126 | } 127 | // mesh-group-enable 128 | // mesh-group 129 | // interface-type 130 | if config.Config.InterfaceType == nil { 131 | interfaceType := "point-to-point" 132 | if ifaceType == kernel.IF_TYPE_BROADCAST { 133 | interfaceType = "broadcast" 134 | } 135 | config.Config.InterfaceType = &interfaceType 136 | } 137 | // enable 138 | if config.Config.Enable == nil { 139 | enable := true 140 | config.Config.Enable = &enable 141 | } 142 | // tag 143 | // tag64 144 | // node-flag 145 | if config.Config.NodeFlag == nil { 146 | nodeFlag := false 147 | config.Config.NodeFlag = &nodeFlag 148 | } 149 | // hello-authentication 150 | // hello-interval 151 | if config.HelloInterval.Config.Value == nil { 152 | value := uint16(10) 153 | config.HelloInterval.Config.Value = &value 154 | } 155 | if config.HelloInterval.Level1.Config.Value == nil { 156 | value := *config.HelloInterval.Config.Value 157 | config.HelloInterval.Level1.Config.Value = &value 158 | } 159 | if config.HelloInterval.Level2.Config.Value == nil { 160 | value := *config.HelloInterval.Config.Value 161 | config.HelloInterval.Level2.Config.Value = &value 162 | } 163 | // hello-multiplier 164 | if config.HelloMultiplier.Config.Value == nil { 165 | value := uint16(3) 166 | config.HelloMultiplier.Config.Value = &value 167 | } 168 | if config.HelloMultiplier.Level1.Config.Value == nil { 169 | value := *config.HelloMultiplier.Config.Value 170 | config.HelloMultiplier.Level1.Config.Value = &value 171 | } 172 | if config.HelloMultiplier.Level2.Config.Value == nil { 173 | value := *config.HelloMultiplier.Config.Value 174 | config.HelloMultiplier.Level2.Config.Value = &value 175 | } 176 | // priority 177 | if config.Priority.Config.Value == nil { 178 | value := uint8(64) 179 | config.Priority.Config.Value = &value 180 | } 181 | if config.Priority.Level1.Config.Value == nil { 182 | value := *config.Priority.Config.Value 183 | config.Priority.Level1.Config.Value = &value 184 | } 185 | if config.Priority.Level2.Config.Value == nil { 186 | value := *config.Priority.Config.Value 187 | config.Priority.Level2.Config.Value = &value 188 | } 189 | // metric 190 | if config.Metric.Config.Value == nil { 191 | value := *isisConfig.DefaultMetric.Config.Value 192 | config.Metric.Config.Value = &value 193 | } 194 | if config.Metric.Level1.Config.Value == nil { 195 | value := *config.Metric.Config.Value 196 | config.Metric.Level1.Config.Value = &value 197 | } 198 | if config.Metric.Level2.Config.Value == nil { 199 | value := *config.Metric.Config.Value 200 | config.Metric.Level2.Config.Value = &value 201 | } 202 | // bfd 203 | // address-families 204 | config.InterfaceAddressFamiliesDefaults(isisConfig) 205 | for _, af := range config.AddressFamilies { 206 | af.fillDefaults() 207 | } 208 | // mpls 209 | // fast-reroute 210 | // topologies 211 | for _, topo := range config.Topologies { 212 | topo.fillDefaults() 213 | } 214 | } 215 | 216 | func (config *IsisConfig) fillDefaults() { 217 | // enable 218 | if config.Config.Enable == nil { 219 | enable := true 220 | config.Config.Enable = &enable 221 | } 222 | // level-type 223 | if config.Config.LevelType == nil { 224 | levelType := "level-all" 225 | config.Config.LevelType = &levelType 226 | } 227 | // system-id 228 | // maximum-area-addresses 229 | if config.Config.MaximumAreaAddresses == nil { 230 | maximumAreaAddresses := uint8(3) 231 | config.Config.MaximumAreaAddresses = &maximumAreaAddresses 232 | } 233 | // area-address 234 | // lsp-mtu 235 | if config.Config.LspMtu == nil { 236 | lspMtu := uint16(1492) 237 | config.Config.LspMtu = &lspMtu 238 | } 239 | // lsp-lifetime 240 | if config.Config.LspLifetime == nil { 241 | lspLifetime := uint16(1200) 242 | config.Config.LspLifetime = &lspLifetime 243 | } 244 | // lsp-refresh 245 | if config.Config.LspRefresh == nil { 246 | lspRefresh := uint16(900) 247 | config.Config.LspRefresh = &lspRefresh 248 | } 249 | // poi-tlv 250 | if config.Config.PoiTlv == nil { 251 | poiTlv := false 252 | config.Config.PoiTlv = &poiTlv 253 | } 254 | // graceful-restart 255 | if config.GracefulRestart.Config.Enable == nil { 256 | enable := false 257 | config.GracefulRestart.Config.Enable = &enable 258 | } 259 | if config.GracefulRestart.Config.HelperEnable == nil { 260 | helperEnable := true 261 | config.GracefulRestart.Config.HelperEnable = &helperEnable 262 | } 263 | // nsr 264 | if config.Nsr.Config.Enable == nil { 265 | enable := false 266 | config.Nsr.Config.Enable = &enable 267 | } 268 | // node-tags 269 | for _, nodeTag := range config.NodeTags { 270 | nodeTag.fillDefaults() 271 | } 272 | // metric-type 273 | if config.MetricType.Config.Value == nil { 274 | value := "wide-only" 275 | config.MetricType.Config.Value = &value 276 | } 277 | if config.MetricType.Level1.Config.Value == nil { 278 | value := *config.MetricType.Config.Value 279 | config.MetricType.Level1.Config.Value = &value 280 | } 281 | if config.MetricType.Level2.Config.Value == nil { 282 | value := *config.MetricType.Config.Value 283 | config.MetricType.Level2.Config.Value = &value 284 | } 285 | // default-metric 286 | if config.DefaultMetric.Config.Value == nil { 287 | value := uint32(10) 288 | config.DefaultMetric.Config.Value = &value 289 | } 290 | // auto-cost 291 | // authentication 292 | // address-families 293 | config.AddressFamiliesDefaults() 294 | for _, af := range config.AddressFamilies { 295 | af.fillDefaults() 296 | } 297 | // mpls 298 | // spf-control 299 | // fast-reroute 300 | // preference 301 | // overload 302 | // overload-max-metric 303 | // topologies 304 | for _, topo := range config.Topologies { 305 | topo.fillDefaults() 306 | } 307 | // interfaces 308 | for _, iface := range config.Interfaces { 309 | iface.fillDefaults(config) 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /internal/pkg/isis/config/parse.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import ( 21 | "bytes" 22 | "strconv" 23 | 24 | _ "github.com/sirupsen/logrus" 25 | 26 | "github.com/m-asama/golsr/pkg/isis/packet" 27 | ) 28 | 29 | func ParseSystemId(systemIdStr string) [packet.SYSTEM_ID_LENGTH]byte { 30 | var tmp int64 31 | var systemId [packet.SYSTEM_ID_LENGTH]byte 32 | tmp, _ = strconv.ParseInt(systemIdStr[0:2], 16, 16) 33 | systemId[0] = byte(tmp) 34 | tmp, _ = strconv.ParseInt(systemIdStr[2:4], 16, 16) 35 | systemId[1] = byte(tmp) 36 | tmp, _ = strconv.ParseInt(systemIdStr[5:7], 16, 16) 37 | systemId[2] = byte(tmp) 38 | tmp, _ = strconv.ParseInt(systemIdStr[7:9], 16, 16) 39 | systemId[3] = byte(tmp) 40 | tmp, _ = strconv.ParseInt(systemIdStr[10:12], 16, 16) 41 | systemId[4] = byte(tmp) 42 | tmp, _ = strconv.ParseInt(systemIdStr[12:14], 16, 16) 43 | systemId[5] = byte(tmp) 44 | return systemId 45 | } 46 | 47 | func ParseAreaAddresses(areaAddressesStrs []*string) [][]byte { 48 | areaAddresses := make([][]byte, len(areaAddressesStrs)) 49 | for i, areaAddressStr := range areaAddressesStrs { 50 | var tmp int64 51 | areaAddress := make([]byte, 0) 52 | tmp, _ = strconv.ParseInt((*areaAddressStr)[0:2], 16, 16) 53 | areaAddress = append(areaAddress, byte(tmp)) 54 | if len(*areaAddressStr) > 3 { 55 | tmp, _ = strconv.ParseInt((*areaAddressStr)[3:5], 16, 16) 56 | areaAddress = append(areaAddress, byte(tmp)) 57 | tmp, _ = strconv.ParseInt((*areaAddressStr)[5:7], 16, 16) 58 | areaAddress = append(areaAddress, byte(tmp)) 59 | } 60 | if len(*areaAddressStr) > 8 { 61 | tmp, _ = strconv.ParseInt((*areaAddressStr)[8:10], 16, 16) 62 | areaAddress = append(areaAddress, byte(tmp)) 63 | tmp, _ = strconv.ParseInt((*areaAddressStr)[10:12], 16, 16) 64 | areaAddress = append(areaAddress, byte(tmp)) 65 | } 66 | if len(*areaAddressStr) > 13 { 67 | tmp, _ = strconv.ParseInt((*areaAddressStr)[13:15], 16, 16) 68 | areaAddress = append(areaAddress, byte(tmp)) 69 | tmp, _ = strconv.ParseInt((*areaAddressStr)[15:17], 16, 16) 70 | areaAddress = append(areaAddress, byte(tmp)) 71 | } 72 | areaAddresses[i] = areaAddress 73 | } 74 | // XXX: 75 | for i := 0; i < len(areaAddresses); i++ { 76 | for j := 0; j < len(areaAddresses); j++ { 77 | if i == j { 78 | break 79 | } 80 | if bytes.Compare(areaAddresses[i], areaAddresses[j]) < 0 { 81 | tmp := areaAddresses[i] 82 | areaAddresses[i] = areaAddresses[j] 83 | areaAddresses[j] = tmp 84 | } 85 | } 86 | } 87 | return areaAddresses 88 | } 89 | -------------------------------------------------------------------------------- /internal/pkg/isis/config/structs_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import ( 21 | "bytes" 22 | "fmt" 23 | "github.com/spf13/viper" 24 | "testing" 25 | ) 26 | 27 | func TestConfig(t *testing.T) { 28 | var err error 29 | config := []byte(` 30 | [config] 31 | enable = true 32 | [authentication.config] 33 | key = "akey" 34 | crypto-algorithm = "ca" 35 | [authentication.level-1.config] 36 | key = "akey1" 37 | crypto-algorithm = "ca1" 38 | 39 | [[address-families]] 40 | [address-families.config] 41 | address-family = "ipv4" 42 | enable = true 43 | 44 | [[address-families]] 45 | [address-families.config] 46 | address-family = "ipv6" 47 | enable = true 48 | 49 | [[interfaces]] 50 | [interfaces.config] 51 | name = "hoge" 52 | [[interfaces.address-families]] 53 | [interfaces.address-families.config] 54 | address-family = "ipv4" 55 | [[interfaces.address-families]] 56 | [interfaces.address-families.config] 57 | address-family = "ipv6" 58 | 59 | [[interfaces]] 60 | [interfaces.config] 61 | name = "piyo" 62 | `) 63 | c := &IsisConfig{} 64 | v := viper.New() 65 | v.SetConfigType("toml") 66 | err = v.ReadConfig(bytes.NewBuffer(config)) 67 | if err != nil { 68 | t.Fatalf("failed ReadConfig: %#v", err) 69 | } 70 | err = v.UnmarshalExact(c) 71 | if err != nil { 72 | t.Fatalf("failed UnmarshalExact: %#v", err) 73 | } 74 | //t.Fatalf("%t", *c.Config.Enable) 75 | //t.Fatalf("*c.Interfaces[0].Config.Name = %s", *c.Interfaces[0].Config.Name) 76 | //t.Fatalf("*c.AddressFamilies[0].Config.AddressFamily = %s", *c.AddressFamilies[0].Config.AddressFamily) 77 | var ss []string 78 | for _, af := range c.AddressFamilies { 79 | ss = append(ss, fmt.Sprintf("*af.Config.AddressFamily = %s", *af.Config.AddressFamily)) 80 | } 81 | //t.Fatalf("%s", ss) 82 | //t.Fatalf("xx = %s", *c.Interfaces[0].AddressFamilies[0].Config.AddressFamily) 83 | } 84 | -------------------------------------------------------------------------------- /internal/pkg/isis/config/validate.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import ( 21 | "errors" 22 | "regexp" 23 | 24 | "github.com/m-asama/golsr/internal/pkg/kernel" 25 | ) 26 | 27 | func (config *NodeTag) validate() error { 28 | var err error 29 | return err 30 | } 31 | 32 | func (config *AddressFamily) validate() error { 33 | var err error 34 | return err 35 | } 36 | 37 | func (config *Topology) validate() error { 38 | var err error 39 | return err 40 | } 41 | 42 | func (config *InterfaceAddressFamily) validate() error { 43 | var err error 44 | return err 45 | } 46 | 47 | func (config *InterfaceTopology) validate() error { 48 | var err error 49 | return err 50 | } 51 | 52 | func (config *Interface) validate() error { 53 | var err error 54 | if config.Config.Name == nil { 55 | return errors.New("interface name not defined") 56 | } 57 | if !kernel.IfaceExists(*config.Config.Name) { 58 | return errors.New("interface not exists") 59 | } 60 | for _, af := range config.AddressFamilies { 61 | err = af.validate() 62 | if err != nil { 63 | return err 64 | } 65 | } 66 | for _, topo := range config.Topologies { 67 | err = topo.validate() 68 | if err != nil { 69 | return err 70 | } 71 | } 72 | return err 73 | } 74 | 75 | func (config *IsisConfig) validate() error { 76 | var err error 77 | if config.Config.SystemId == nil { 78 | return errors.New("system-id not defined") 79 | } 80 | err = validateSystemId(*config.Config.SystemId) 81 | if err != nil { 82 | return err 83 | } 84 | if len(config.Config.AreaAddress) == 0 { 85 | return errors.New("area-address-list not defined") 86 | } 87 | err = validateAreaAddress(config.Config.AreaAddress) 88 | if err != nil { 89 | return err 90 | } 91 | for _, nodeTag := range config.NodeTags { 92 | err = nodeTag.validate() 93 | if err != nil { 94 | return err 95 | } 96 | } 97 | for _, af := range config.AddressFamilies { 98 | err = af.validate() 99 | if err != nil { 100 | return err 101 | } 102 | } 103 | for _, topo := range config.Topologies { 104 | err = topo.validate() 105 | if err != nil { 106 | return err 107 | } 108 | } 109 | for _, iface := range config.Interfaces { 110 | err = iface.validate() 111 | if err != nil { 112 | return err 113 | } 114 | } 115 | return err 116 | } 117 | 118 | func validateSystemId(systemId string) error { 119 | validSystemId := regexp.MustCompile(`^[0-9A-Fa-f]{4}\.[0-9A-Fa-f]{4}\.[0-9A-Fa-f]{4}$`) 120 | if !validSystemId.MatchString(systemId) { 121 | return errors.New("system-id invalid") 122 | } 123 | return nil 124 | } 125 | 126 | func validateAreaAddress(areaAddresses []*string) error { 127 | validAreaAddress := regexp.MustCompile(`^[0-9A-Fa-f]{2}(\.[0-9A-Fa-f]{4}){0,3}$`) 128 | for _, areaAddress := range areaAddresses { 129 | if areaAddress == nil { 130 | return errors.New("area-address-list invalid") 131 | } 132 | if !validAreaAddress.MatchString(*areaAddress) { 133 | return errors.New("area-address-list invalid") 134 | } 135 | } 136 | return nil 137 | } 138 | -------------------------------------------------------------------------------- /internal/pkg/kernel/kernel.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package kernel 19 | 20 | import ( 21 | "encoding/binary" 22 | "net" 23 | 24 | log "github.com/sirupsen/logrus" 25 | 26 | "github.com/vishvananda/netlink" 27 | "golang.org/x/sys/unix" 28 | ) 29 | 30 | type IfType int 31 | 32 | const ( 33 | _ IfType = iota 34 | IF_TYPE_LOOPBACK = 1 35 | IF_TYPE_BROADCAST = 2 36 | IF_TYPE_POINTTOPOINT = 3 37 | ) 38 | 39 | type Ipv4Address struct { 40 | Address uint32 41 | PrefixLength int 42 | ScopeHost bool 43 | } 44 | 45 | type Ipv6Address struct { 46 | Address [4]uint32 47 | PrefixLength int 48 | ScopeLink bool 49 | ScopeHost bool 50 | } 51 | 52 | type Interface struct { 53 | IfIndex int 54 | Name string 55 | IfType IfType 56 | HardwareAddr []byte 57 | Mtu int 58 | Up bool 59 | Ipv4Addresses []*Ipv4Address 60 | Ipv6Addresses []*Ipv6Address 61 | } 62 | 63 | type KernelStatus struct { 64 | Interfaces []*Interface 65 | } 66 | 67 | func NewIpv4Address(addr *netlink.Addr) *Ipv4Address { 68 | if len(addr.IP) != 4 { 69 | return nil 70 | } 71 | ipv4Address := &Ipv4Address{} 72 | ipv4Address.Address = binary.BigEndian.Uint32(addr.IP[0:4]) 73 | ipv4Address.PrefixLength, _ = addr.Mask.Size() 74 | ipv4Address.ScopeHost = (addr.Scope == unix.RT_SCOPE_HOST) 75 | return ipv4Address 76 | } 77 | 78 | func NewIpv6Address(addr *netlink.Addr) *Ipv6Address { 79 | if len(addr.IP) != 16 { 80 | return nil 81 | } 82 | ipv6Address := &Ipv6Address{} 83 | ipv6Address.Address[0] = binary.BigEndian.Uint32(addr.IP[0:4]) 84 | ipv6Address.Address[1] = binary.BigEndian.Uint32(addr.IP[4:8]) 85 | ipv6Address.Address[2] = binary.BigEndian.Uint32(addr.IP[8:12]) 86 | ipv6Address.Address[3] = binary.BigEndian.Uint32(addr.IP[12:16]) 87 | ipv6Address.PrefixLength, _ = addr.Mask.Size() 88 | ipv6Address.ScopeLink = (addr.Scope == unix.RT_SCOPE_LINK) 89 | ipv6Address.ScopeHost = (addr.Scope == unix.RT_SCOPE_HOST) 90 | return ipv6Address 91 | } 92 | 93 | func ifType(flags net.Flags) IfType { 94 | var ifType IfType 95 | if (flags & net.FlagLoopback) != 0 { 96 | ifType = IF_TYPE_LOOPBACK 97 | } 98 | if (flags & net.FlagBroadcast) != 0 { 99 | ifType = IF_TYPE_BROADCAST 100 | } 101 | if (flags & net.FlagPointToPoint) != 0 { 102 | ifType = IF_TYPE_POINTTOPOINT 103 | } 104 | return ifType 105 | } 106 | 107 | func NewInterface(attrs *netlink.LinkAttrs) *Interface { 108 | if attrs == nil { 109 | return nil 110 | } 111 | ifType := ifType(attrs.Flags) 112 | if ifType == 0 { 113 | return nil 114 | } 115 | iface := &Interface{} 116 | iface.IfIndex = attrs.Index 117 | iface.Name = attrs.Name 118 | iface.IfType = ifType 119 | iface.HardwareAddr = attrs.HardwareAddr 120 | iface.Mtu = attrs.MTU 121 | iface.Up = ((attrs.Flags & net.FlagUp) != 0) 122 | iface.Ipv4Addresses = make([]*Ipv4Address, 0) 123 | iface.Ipv6Addresses = make([]*Ipv6Address, 0) 124 | return iface 125 | } 126 | 127 | func NewKernelStatus() *KernelStatus { 128 | status := &KernelStatus{} 129 | status.Interfaces = make([]*Interface, 0) 130 | 131 | links, err := netlink.LinkList() 132 | if err != nil { 133 | return nil 134 | } 135 | for _, link := range links { 136 | iface := NewInterface(link.Attrs()) 137 | if iface == nil { 138 | continue 139 | } 140 | addr4s, err := netlink.AddrList(link, unix.AF_INET) 141 | if err != nil { 142 | return nil 143 | } 144 | for _, addr4 := range addr4s { 145 | ipv4Address := NewIpv4Address(&addr4) 146 | if ipv4Address != nil { 147 | iface.Ipv4Addresses = append(iface.Ipv4Addresses, ipv4Address) 148 | } 149 | } 150 | addr6s, err := netlink.AddrList(link, unix.AF_INET6) 151 | if err != nil { 152 | return nil 153 | } 154 | for _, addr6 := range addr6s { 155 | ipv6Address := NewIpv6Address(&addr6) 156 | if ipv6Address != nil { 157 | iface.Ipv6Addresses = append(iface.Ipv6Addresses, ipv6Address) 158 | } 159 | } 160 | status.Interfaces = append(status.Interfaces, iface) 161 | } 162 | 163 | return status 164 | } 165 | 166 | func Serve(status chan<- *KernelStatus) { 167 | log.Debugf("enter") 168 | defer log.Debugf("exit") 169 | addrCh := make(chan netlink.AddrUpdate) 170 | addrDone := make(chan struct{}) 171 | netlink.AddrSubscribe(addrCh, addrDone) 172 | linkCh := make(chan netlink.LinkUpdate) 173 | linkDone := make(chan struct{}) 174 | netlink.LinkSubscribe(linkCh, linkDone) 175 | status <- NewKernelStatus() 176 | for { 177 | select { 178 | case <-addrCh: 179 | case <-linkCh: 180 | } 181 | status <- NewKernelStatus() 182 | } 183 | } 184 | 185 | func IfaceExists(name string) bool { 186 | links, err := netlink.LinkList() 187 | if err != nil { 188 | return false 189 | } 190 | for _, link := range links { 191 | attrs := link.Attrs() 192 | if attrs.Name == name { 193 | return true 194 | } 195 | } 196 | return false 197 | } 198 | 199 | func IfaceType(name string) IfType { 200 | links, err := netlink.LinkList() 201 | if err != nil { 202 | return IfType(0) 203 | } 204 | for _, link := range links { 205 | attrs := link.Attrs() 206 | if attrs.Name == name { 207 | return ifType(attrs.Flags) 208 | } 209 | } 210 | return IfType(0) 211 | } 212 | -------------------------------------------------------------------------------- /internal/pkg/kernel/kernel_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package kernel 19 | 20 | import ( 21 | "bytes" 22 | "fmt" 23 | "testing" 24 | ) 25 | 26 | func TestKernel(t *testing.T) { 27 | var b bytes.Buffer 28 | info := NewKernelStatus() 29 | if info == nil { 30 | t.Fatalf("NewKernelStatus") 31 | } 32 | for _, iface := range info.Interfaces { 33 | fmt.Fprintf(&b, "InterfaceName = %s\n", iface.Name) 34 | for _, addr4 := range iface.Ipv4Addresses { 35 | fmt.Fprintf(&b, "\t%08x/%d\n", addr4.Address, addr4.PrefixLength) 36 | } 37 | for _, addr6 := range iface.Ipv6Addresses { 38 | fmt.Fprintf(&b, "\t%08x:%08x:%08x:%08x/%d %t\n", 39 | addr6.Address[0], addr6.Address[1], addr6.Address[2], addr6.Address[3], 40 | addr6.PrefixLength, addr6.ScopeLink) 41 | } 42 | } 43 | //t.Fatalf("\n%s", b.String()) 44 | } 45 | -------------------------------------------------------------------------------- /internal/pkg/ospf/command/command.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package command 19 | 20 | import ( 21 | "context" 22 | "encoding/json" 23 | "fmt" 24 | "net" 25 | "os" 26 | "strconv" 27 | "time" 28 | 29 | "github.com/spf13/cobra" 30 | "google.golang.org/grpc" 31 | 32 | api "github.com/m-asama/golsr/api/ospf" 33 | ) 34 | 35 | var globalOpts struct { 36 | Host string 37 | Port int 38 | Debug bool 39 | Quiet bool 40 | Json bool 41 | GenCmpl bool 42 | BashCmplFile string 43 | } 44 | 45 | var client api.GoospfApiClient 46 | var ctx context.Context 47 | 48 | func printError(err error) { 49 | if globalOpts.Json { 50 | j, _ := json.Marshal(struct { 51 | Error string `json:"error"` 52 | }{Error: err.Error()}) 53 | fmt.Println(string(j)) 54 | } else { 55 | fmt.Println(err) 56 | } 57 | } 58 | 59 | func exitWithError(err error) { 60 | printError(err) 61 | os.Exit(1) 62 | } 63 | 64 | func newClient(ctx context.Context) (api.GoospfApiClient, error) { 65 | grpcOpts := []grpc.DialOption{grpc.WithTimeout(time.Second), grpc.WithBlock()} 66 | grpcOpts = append(grpcOpts, grpc.WithInsecure()) 67 | 68 | target := net.JoinHostPort(globalOpts.Host, strconv.Itoa(globalOpts.Port)) 69 | if target == "" { 70 | target = ":50052" 71 | } 72 | 73 | conn, err := grpc.DialContext(ctx, target, grpcOpts...) 74 | if err != nil { 75 | return nil, err 76 | } 77 | return api.NewGoospfApiClient(conn), nil 78 | } 79 | 80 | func NewRootCmd() *cobra.Command { 81 | cobra.EnablePrefixMatching = true 82 | rootCmd := &cobra.Command{ 83 | Use: "goospf", 84 | PersistentPreRun: func(cmd *cobra.Command, args []string) { 85 | if !globalOpts.GenCmpl { 86 | var err error 87 | ctx = context.Background() 88 | client, err = newClient(ctx) 89 | if err != nil { 90 | exitWithError(err) 91 | } 92 | } 93 | }, 94 | Run: func(cmd *cobra.Command, args []string) { 95 | if globalOpts.GenCmpl { 96 | cmd.GenBashCompletionFile(globalOpts.BashCmplFile) 97 | } else { 98 | cmd.HelpFunc()(cmd, args) 99 | } 100 | }, 101 | PersistentPostRun: func(cmd *cobra.Command, args []string) { 102 | }, 103 | } 104 | 105 | rootCmd.PersistentFlags().StringVarP(&globalOpts.Host, "host", "u", "127.0.0.1", "host") 106 | rootCmd.PersistentFlags().IntVarP(&globalOpts.Port, "port", "p", 50052, "port") 107 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Json, "json", "j", false, "use json format to output format") 108 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Debug, "debug", "d", false, "use debug") 109 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.Quiet, "quiet", "q", false, "use quiet") 110 | rootCmd.PersistentFlags().BoolVarP(&globalOpts.GenCmpl, "gen-cmpl", "c", false, "generate completion file") 111 | rootCmd.PersistentFlags().StringVarP(&globalOpts.BashCmplFile, "bash-cmpl-file", "", "goospf-completion.bash", 112 | "bash cmpl filename") 113 | 114 | enableCmd := &cobra.Command{ 115 | Use: "enable", 116 | Run: func(cmd *cobra.Command, args []string) { 117 | response, _ := client.Enable(ctx, &api.EnableRequest{}) 118 | fmt.Println(response.Result) 119 | }, 120 | } 121 | rootCmd.AddCommand(enableCmd) 122 | 123 | disableCmd := &cobra.Command{ 124 | Use: "disable", 125 | Run: func(cmd *cobra.Command, args []string) { 126 | response, _ := client.Disable(ctx, &api.DisableRequest{}) 127 | fmt.Println(response.Result) 128 | }, 129 | } 130 | rootCmd.AddCommand(disableCmd) 131 | 132 | /* 133 | interfaceCmd := NewInterfaceCmd() 134 | rootCmd.AddCommand(interfaceCmd) 135 | 136 | databaseCmd := NewDatabaseCmd() 137 | rootCmd.AddCommand(databaseCmd) 138 | 139 | routeCmd := NewRouteCmd() 140 | rootCmd.AddCommand(routeCmd) 141 | */ 142 | 143 | return rootCmd 144 | } 145 | -------------------------------------------------------------------------------- /internal/pkg/ospf/config/config.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import ( 21 | log "github.com/sirupsen/logrus" 22 | "github.com/spf13/viper" 23 | "os" 24 | "os/signal" 25 | "path/filepath" 26 | "syscall" 27 | //yaml "gopkg.in/yaml.v2" 28 | ) 29 | 30 | func detectConfigFileType(path, def string) string { 31 | switch ext := filepath.Ext(path); ext { 32 | case ".toml": 33 | return "toml" 34 | case ".yaml", ".yml": 35 | return "yaml" 36 | case ".json": 37 | return "json" 38 | default: 39 | return def 40 | } 41 | } 42 | 43 | func Serve(path, format string, configCh chan *OspfConfig) { 44 | 45 | //log.Info("ReadConfigfileServe started") 46 | 47 | sigCh := make(chan os.Signal, 1) 48 | signal.Notify(sigCh, syscall.SIGHUP) 49 | 50 | // Update config file type, if detectable 51 | format = detectConfigFileType(path, format) 52 | 53 | cnt := 0 54 | for { 55 | c := &OspfConfig{} 56 | v := viper.New() 57 | v.SetConfigFile(path) 58 | v.SetConfigType(format) 59 | var err error 60 | if err = v.ReadInConfig(); err != nil { 61 | goto ERROR 62 | } 63 | if err = v.UnmarshalExact(c); err != nil { 64 | goto ERROR 65 | } 66 | c.fillDefaults() 67 | if err = c.validate(); err != nil { 68 | goto ERROR 69 | } 70 | if cnt == 0 { 71 | log.WithFields(log.Fields{ 72 | "Topic": "Config", 73 | }).Info("Finished reading the config file") 74 | } 75 | /* 76 | if err = v.WriteConfigAs("/tmp/goospfd.toml"); err != nil { 77 | log.Info("WriteConfigAs failed", err) 78 | } else { 79 | log.Info("WriteConfigAs success") 80 | } 81 | bs, err = yaml.Marshal(c) 82 | if err != nil { 83 | log.Info("yaml.Marshal error") 84 | } else { 85 | fmt.Printf("\n%s", string(bs)) 86 | } 87 | */ 88 | 89 | cnt++ 90 | configCh <- c 91 | goto NEXT 92 | ERROR: 93 | if cnt == 0 { 94 | log.WithFields(log.Fields{ 95 | "Topic": "Config", 96 | "Error": err, 97 | }).Fatalf("Can't read config file %s", path) 98 | } else { 99 | log.WithFields(log.Fields{ 100 | "Topic": "Config", 101 | "Error": err, 102 | }).Warningf("Can't read config file %s", path) 103 | } 104 | NEXT: 105 | <-sigCh 106 | log.WithFields(log.Fields{ 107 | "Topic": "Config", 108 | }).Info("Reload the config file") 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /internal/pkg/ospf/config/defaults.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import () 21 | 22 | func (config *OspfConfig) fillDefaults() { 23 | } 24 | -------------------------------------------------------------------------------- /internal/pkg/ospf/config/parse.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import () 21 | -------------------------------------------------------------------------------- /internal/pkg/ospf/config/structs_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import ( 21 | "bytes" 22 | "fmt" 23 | "github.com/spf13/viper" 24 | "testing" 25 | ) 26 | 27 | func TestConfig(t *testing.T) { 28 | var err error 29 | config := []byte(` 30 | [config] 31 | enable = true 32 | [[areas]] 33 | [areas.config] 34 | area-id = "0.0.0.0" 35 | [[areas.interfaces]] 36 | [areas.interfaces.config] 37 | name = "eth0" 38 | [[areas]] 39 | [areas.config] 40 | area-id = "0.0.0.1" 41 | [[areas.interfaces]] 42 | [areas.interfaces.config] 43 | name = "eth1" 44 | `) 45 | c := &OspfConfig{} 46 | v := viper.New() 47 | v.SetConfigType("toml") 48 | err = v.ReadConfig(bytes.NewBuffer(config)) 49 | if err != nil { 50 | t.Fatalf("failed ReadConfig: %#v", err) 51 | } 52 | err = v.UnmarshalExact(c) 53 | if err != nil { 54 | t.Fatalf("failed UnmarshalExact: %#v", err) 55 | } 56 | var ss []string 57 | for _, area := range c.Areas { 58 | ss = append(ss, fmt.Sprintf("*area.Config.AreaId = %s", *area.Config.AreaId)) 59 | } 60 | //t.Fatalf("%s", ss) 61 | } 62 | -------------------------------------------------------------------------------- /internal/pkg/ospf/config/validate.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package config 19 | 20 | import () 21 | 22 | func (config *OspfConfig) validate() error { 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /internal/pkg/util/ip.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package util 19 | 20 | import ( 21 | "net" 22 | ) 23 | 24 | func Plen2snmask4(plen uint8) uint32 { 25 | return uint32(((uint64(1) << plen) - 1) << (32 - plen)) 26 | } 27 | 28 | func Snmask42plen(snmask uint32) uint8 { 29 | var i uint8 30 | for i = 0; i <= 32; i++ { 31 | if snmask == Plen2snmask4(i) { 32 | return i 33 | } 34 | } 35 | return 32 36 | } 37 | 38 | func Ipv4Uint32ToString(addr uint32) string { 39 | ip := make([]byte, 4) 40 | for i := 0; i < 4; i++ { 41 | ip[i] = byte(addr >> uint(((3 - i%4) * 8))) 42 | } 43 | return (net.IP(ip)).String() 44 | } 45 | 46 | func Ipv6Uint32ArrayToString(addr [4]uint32) string { 47 | ip := make([]byte, 16) 48 | for i := 0; i < 16; i++ { 49 | ip[i] = byte(addr[i/4] >> uint(((3 - i%4) * 8))) 50 | } 51 | return (net.IP(ip)).String() 52 | } 53 | -------------------------------------------------------------------------------- /pkg/isis/packet/pdu_base.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "encoding/binary" 23 | "errors" 24 | "fmt" 25 | ) 26 | 27 | type pduBase struct { 28 | originalData []byte 29 | 30 | irpDiscriminator uint8 31 | lengthIndicator uint8 32 | verProtoIdExtension uint8 33 | idLength uint8 34 | pduType PduType 35 | version uint8 36 | reserved uint8 37 | maximumAreaAddress uint8 38 | pduLength uint16 39 | 40 | tlvs []IsisTlv 41 | } 42 | 43 | func (base *pduBase) init() { 44 | base.originalData = make([]byte, 0) 45 | 46 | base.irpDiscriminator = 0x83 47 | base.verProtoIdExtension = 0x01 48 | base.idLength = SYSTEM_ID_LENGTH 49 | base.version = 0x01 50 | base.maximumAreaAddress = 0x03 51 | 52 | base.tlvs = make([]IsisTlv, 0) 53 | } 54 | 55 | func (base *pduBase) valid() bool { 56 | if base.irpDiscriminator != 0x83 || 57 | base.verProtoIdExtension != 0x01 || 58 | base.idLength != SYSTEM_ID_LENGTH || 59 | base.version != 0x01 || 60 | base.maximumAreaAddress != 0x03 { 61 | return false 62 | } 63 | return true 64 | } 65 | 66 | func (base *pduBase) StringFixed() string { 67 | var b bytes.Buffer 68 | fmt.Fprintf(&b, "irpDiscriminator 0x%02x\n", base.irpDiscriminator) 69 | fmt.Fprintf(&b, "lengthIndicator 0x%02x\n", base.lengthIndicator) 70 | fmt.Fprintf(&b, "verProtoIdExtension 0x%02x\n", base.verProtoIdExtension) 71 | fmt.Fprintf(&b, "idLength %d\n", base.idLength) 72 | fmt.Fprintf(&b, "pduType %s(%d)\n", base.pduType.String(), base.pduType) 73 | fmt.Fprintf(&b, "version 0x%02x\n", base.version) 74 | fmt.Fprintf(&b, "reserved 0x%02x\n", base.reserved) 75 | fmt.Fprintf(&b, "maximumAreaAddress %d\n", base.maximumAreaAddress) 76 | fmt.Fprintf(&b, "pduLength %d\n", base.pduLength) 77 | return b.String() 78 | } 79 | 80 | func (base *pduBase) StringTlv() string { 81 | var b bytes.Buffer 82 | for i, tlv := range base.tlvs { 83 | fmt.Fprintf(&b, "TLV[%d]\n", i) 84 | fmt.Fprintf(&b, tlv.String()) 85 | } 86 | return b.String() 87 | } 88 | 89 | func (base *pduBase) DecodeFromBytes(data []byte) error { 90 | base.originalData = make([]byte, len(data)) 91 | copy(base.originalData, data) 92 | if len(data) < 8 { 93 | return errors.New("pduBase.DecodeFromBytes: data length too short") 94 | } 95 | base.irpDiscriminator = data[0] 96 | base.lengthIndicator = data[1] 97 | base.verProtoIdExtension = data[2] 98 | base.idLength = data[3] 99 | if base.idLength == 0 { 100 | base.idLength = 6 101 | } 102 | if base.idLength == 255 { 103 | base.idLength = 0 104 | } 105 | base.pduType = PduType(data[4]) 106 | base.version = data[5] 107 | base.reserved = data[6] 108 | base.maximumAreaAddress = data[7] 109 | if base.maximumAreaAddress == 0 { 110 | base.maximumAreaAddress = 3 111 | } 112 | switch base.pduType { 113 | case PDU_TYPE_LEVEL1_LAN_IIHP, PDU_TYPE_LEVEL2_LAN_IIHP, PDU_TYPE_P2P_IIHP: 114 | if len(data) < int(13+SYSTEM_ID_LENGTH) { 115 | return errors.New("pduBase.DecodeFromBytes: data length too short") 116 | } 117 | base.pduLength = binary.BigEndian.Uint16(data[11+SYSTEM_ID_LENGTH : 13+SYSTEM_ID_LENGTH]) 118 | default: 119 | if len(data) < 10 { 120 | return errors.New("pduBase.DecodeFromBytes: data length too short") 121 | } 122 | base.pduLength = binary.BigEndian.Uint16(data[8:10]) 123 | } 124 | if len(data) != int(base.pduLength) { 125 | s := fmt.Sprintf("pduBase.DecodeFromBytes: data length mismatch %d %d", len(data), int(base.pduLength)) 126 | return errors.New(s) 127 | } 128 | 129 | // TLV 130 | if len(data) >= int(base.lengthIndicator) { 131 | i := int(base.lengthIndicator) 132 | for i < int(base.pduLength) { 133 | if int(base.pduLength) < i+2 { 134 | return errors.New("pduBase.DecodeFromBytes: data length short") 135 | } 136 | t := TlvCode(data[i+0]) 137 | l := int(data[i+1]) 138 | tlv, err := NewTlv(t) 139 | if err != nil { 140 | return err 141 | } 142 | if int(base.pduLength) < i+2+l { 143 | return errors.New("pduBase.DecodeFromBytes: data length short") 144 | } 145 | err = tlv.DecodeFromBytes(data[i : i+2+l]) 146 | if err != nil { 147 | return err 148 | } 149 | base.tlvs = append(base.tlvs, tlv) 150 | i += 2 + l 151 | } 152 | } 153 | 154 | return nil 155 | } 156 | 157 | func (base *pduBase) Serialize() ([]byte, error) { 158 | var pduLength uint16 159 | var tlvs [][]byte 160 | pduLength = uint16(base.lengthIndicator) 161 | tlvs = make([][]byte, len(base.tlvs)) 162 | for i, tlv := range base.tlvs { 163 | var err error 164 | tlvs[i], err = tlv.Serialize() 165 | if err != nil { 166 | return nil, err 167 | } 168 | pduLength += uint16(len(tlvs[i])) 169 | } 170 | base.pduLength = pduLength 171 | data := make([]byte, base.pduLength) 172 | data[0] = base.irpDiscriminator 173 | data[1] = base.lengthIndicator 174 | data[2] = base.verProtoIdExtension 175 | data[3] = base.idLength 176 | if base.idLength == 0 { 177 | data[3] = 255 178 | } 179 | if base.idLength == 6 { 180 | data[3] = 0 181 | } 182 | data[4] = uint8(base.pduType) 183 | data[5] = base.version 184 | data[6] = base.reserved 185 | data[7] = base.maximumAreaAddress 186 | if base.maximumAreaAddress == 3 { 187 | data[7] = 0 188 | } 189 | switch base.pduType { 190 | case PDU_TYPE_LEVEL1_LAN_IIHP, PDU_TYPE_LEVEL2_LAN_IIHP, PDU_TYPE_P2P_IIHP: 191 | binary.BigEndian.PutUint16(data[11+SYSTEM_ID_LENGTH:13+SYSTEM_ID_LENGTH], base.pduLength) 192 | default: 193 | binary.BigEndian.PutUint16(data[8:10], base.pduLength) 194 | } 195 | i := int(base.lengthIndicator) 196 | for _, tlv := range tlvs { 197 | copy(data[i:i+len(tlv)], tlv) 198 | i += len(tlv) 199 | } 200 | return data, nil 201 | } 202 | 203 | func DecodePduFromBytes(data []byte) (IsisPdu, error) { 204 | var pdu IsisPdu 205 | if len(data) < 5 { 206 | return nil, errors.New("DecodePduFromBytes: data length too short") 207 | } 208 | idLength := data[3] 209 | if idLength != 0 { 210 | return nil, errors.New("DecodePduFromBytes: ID Length not supported") 211 | } 212 | pduType := PduType(data[4]) 213 | var err error 214 | switch pduType { 215 | case PDU_TYPE_LEVEL1_LAN_IIHP, PDU_TYPE_LEVEL2_LAN_IIHP, PDU_TYPE_P2P_IIHP: 216 | pdu, err = NewIihPdu(pduType) 217 | case PDU_TYPE_LEVEL1_LSP, PDU_TYPE_LEVEL2_LSP: 218 | pdu, err = NewLsPdu(pduType) 219 | case PDU_TYPE_LEVEL1_CSNP, PDU_TYPE_LEVEL2_CSNP, PDU_TYPE_LEVEL1_PSNP, PDU_TYPE_LEVEL2_PSNP: 220 | pdu, err = NewSnPdu(pduType) 221 | } 222 | if err != nil { 223 | return nil, err 224 | } 225 | err = pdu.DecodeFromBytes(data) 226 | return pdu, err 227 | } 228 | 229 | func (base *pduBase) SetTlv(tlv IsisTlv) error { 230 | tlvs := make([]IsisTlv, 0) 231 | for _, tlvtmp := range base.tlvs { 232 | if tlvtmp.TlvCode() != tlv.TlvCode() { 233 | tlvs = append(tlvs, tlvtmp) 234 | } 235 | } 236 | tlvs = append(tlvs, tlv) 237 | base.tlvs = tlvs 238 | return nil 239 | } 240 | 241 | func (base *pduBase) Tlv(tlvCode TlvCode) (IsisTlv, error) { 242 | for _, tlv := range base.tlvs { 243 | if tlv.TlvCode() == tlvCode { 244 | return tlv, nil 245 | } 246 | } 247 | return nil, nil 248 | } 249 | 250 | func (base *pduBase) AddTlv(tlv IsisTlv) error { 251 | base.tlvs = append(base.tlvs, tlv) 252 | return nil 253 | } 254 | 255 | func (base *pduBase) Tlvs(tlvCode TlvCode) ([]IsisTlv, error) { 256 | tlvs := make([]IsisTlv, 0) 257 | for _, tlv := range base.tlvs { 258 | if tlv.TlvCode() == tlvCode { 259 | tlvs = append(tlvs, tlv) 260 | } 261 | } 262 | return tlvs, nil 263 | } 264 | 265 | func (base *pduBase) ClearTlvs(tlvCode TlvCode) error { 266 | tlvs := make([]IsisTlv, 0) 267 | for _, tlv := range base.tlvs { 268 | if tlv.TlvCode() != tlvCode { 269 | tlvs = append(tlvs, tlv) 270 | } 271 | } 272 | base.tlvs = tlvs 273 | return nil 274 | } 275 | -------------------------------------------------------------------------------- /pkg/isis/packet/pdu_hello.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "encoding/binary" 23 | "errors" 24 | "fmt" 25 | ) 26 | 27 | type IihPdu struct { 28 | base pduBase 29 | 30 | CircuitType CircuitType 31 | sourceId [SYSTEM_ID_LENGTH]byte 32 | HoldingTime uint16 33 | Priority uint8 // LAN 34 | lanId [NEIGHBOUR_ID_LENGTH]byte // LAN 35 | LocalCircuitId uint8 // P2P 36 | } 37 | 38 | func NewIihPdu(pduType PduType) (*IihPdu, error) { 39 | if pduType != PDU_TYPE_LEVEL1_LAN_IIHP && 40 | pduType != PDU_TYPE_LEVEL2_LAN_IIHP && 41 | pduType != PDU_TYPE_P2P_IIHP { 42 | return nil, errors.New("NewIihPdu: pduType invalid") 43 | } 44 | var lengthIndicator uint8 45 | switch pduType { 46 | case PDU_TYPE_LEVEL1_LAN_IIHP, PDU_TYPE_LEVEL2_LAN_IIHP: 47 | lengthIndicator = 14 + SYSTEM_ID_LENGTH + NEIGHBOUR_ID_LENGTH 48 | case PDU_TYPE_P2P_IIHP: 49 | lengthIndicator = 14 + SYSTEM_ID_LENGTH 50 | } 51 | iih := IihPdu{ 52 | base: pduBase{ 53 | lengthIndicator: lengthIndicator, 54 | pduType: pduType, 55 | }, 56 | } 57 | iih.base.init() 58 | return &iih, nil 59 | } 60 | 61 | func (iih *IihPdu) PduType() PduType { 62 | return iih.base.pduType 63 | } 64 | 65 | func (iih *IihPdu) String() string { 66 | var b bytes.Buffer 67 | b.WriteString(iih.base.StringFixed()) 68 | fmt.Fprintf(&b, "CircuitType %s\n", iih.CircuitType.String()) 69 | fmt.Fprintf(&b, "sourceId ") 70 | for t := range iih.sourceId { 71 | fmt.Fprintf(&b, "%02x", t) 72 | } 73 | fmt.Fprintf(&b, "\n") 74 | fmt.Fprintf(&b, "HoldingTime %d\n", iih.HoldingTime) 75 | if iih.base.pduType == PDU_TYPE_LEVEL1_LAN_IIHP || 76 | iih.base.pduType == PDU_TYPE_LEVEL2_LAN_IIHP { 77 | fmt.Fprintf(&b, "Priority %d\n", iih.Priority) 78 | fmt.Fprintf(&b, "lanId ") 79 | for t := range iih.lanId { 80 | fmt.Fprintf(&b, "%02x", t) 81 | } 82 | fmt.Fprintf(&b, "\n") 83 | } 84 | if iih.base.pduType == PDU_TYPE_P2P_IIHP { 85 | fmt.Fprintf(&b, "LocalCircuitId 0x%02x\n", iih.LocalCircuitId) 86 | } 87 | b.WriteString(iih.base.StringTlv()) 88 | return b.String() 89 | } 90 | 91 | func (iih *IihPdu) DecodeFromBytes(data []byte) error { 92 | err := iih.base.DecodeFromBytes(data) 93 | if err != nil { 94 | return err 95 | } 96 | // 97 | // CircuitType 98 | iih.CircuitType = CircuitType(data[8]) 99 | // 100 | // SourceId 101 | copy(iih.sourceId[0:SYSTEM_ID_LENGTH], data[9:9+SYSTEM_ID_LENGTH]) 102 | // 103 | // HoldingTime 104 | iih.HoldingTime = binary.BigEndian.Uint16(data[9+SYSTEM_ID_LENGTH : 11+SYSTEM_ID_LENGTH]) 105 | switch iih.base.pduType { 106 | case PDU_TYPE_LEVEL1_LAN_IIHP, PDU_TYPE_LEVEL2_LAN_IIHP: 107 | // 108 | // Priority 109 | iih.Priority = data[13+SYSTEM_ID_LENGTH] 110 | // 111 | // LanId 112 | copy(iih.lanId[0:NEIGHBOUR_ID_LENGTH], 113 | data[14+SYSTEM_ID_LENGTH:14+SYSTEM_ID_LENGTH+NEIGHBOUR_ID_LENGTH]) 114 | case PDU_TYPE_P2P_IIHP: 115 | // 116 | // LocalCircuitId 117 | iih.LocalCircuitId = data[13+SYSTEM_ID_LENGTH] 118 | default: 119 | return errors.New("IihPdu.DecodeFromBytes: pduType invalid") 120 | } 121 | return nil 122 | } 123 | 124 | func (iih *IihPdu) Serialize() ([]byte, error) { 125 | data, err := iih.base.Serialize() 126 | if err != nil { 127 | return data, err 128 | } 129 | // 130 | // CircuitType 131 | data[8] = uint8(iih.CircuitType) 132 | // 133 | // SourceId 134 | copy(data[9:9+SYSTEM_ID_LENGTH], iih.sourceId[0:SYSTEM_ID_LENGTH]) 135 | // 136 | // HoldingTime 137 | binary.BigEndian.PutUint16(data[9+SYSTEM_ID_LENGTH:11+SYSTEM_ID_LENGTH], iih.HoldingTime) 138 | switch iih.base.pduType { 139 | case PDU_TYPE_LEVEL1_LAN_IIHP, PDU_TYPE_LEVEL2_LAN_IIHP: 140 | // 141 | // Priority 142 | data[13+SYSTEM_ID_LENGTH] = iih.Priority 143 | // 144 | // LanId 145 | copy(data[14+SYSTEM_ID_LENGTH:14+SYSTEM_ID_LENGTH+NEIGHBOUR_ID_LENGTH], 146 | iih.lanId[0:NEIGHBOUR_ID_LENGTH]) 147 | case PDU_TYPE_P2P_IIHP: 148 | // 149 | // LocalCircuitId 150 | data[13+SYSTEM_ID_LENGTH] = iih.LocalCircuitId 151 | default: 152 | return nil, errors.New("IihPdu.Serialize: pduType invalid") 153 | } 154 | return data, nil 155 | } 156 | 157 | func (iih *IihPdu) BaseValid() bool { 158 | return iih.base.valid() 159 | } 160 | 161 | func (iih *IihPdu) SourceId() [SYSTEM_ID_LENGTH]byte { 162 | return iih.sourceId 163 | } 164 | 165 | func (iih *IihPdu) SetSourceId(sourceId [SYSTEM_ID_LENGTH]byte) error { 166 | iih.sourceId = sourceId 167 | return nil 168 | } 169 | 170 | func (iih *IihPdu) LanId() [NEIGHBOUR_ID_LENGTH]byte { 171 | return iih.lanId 172 | } 173 | 174 | func (iih *IihPdu) SetLanId(lanId [NEIGHBOUR_ID_LENGTH]byte) error { 175 | iih.lanId = lanId 176 | return nil 177 | } 178 | 179 | func (iih *IihPdu) SetAreaAddressesTlv(tlv *areaAddressesTlv) error { 180 | return iih.base.SetTlv(tlv) 181 | } 182 | 183 | func (iih *IihPdu) AreaAddressesTlv() (*areaAddressesTlv, error) { 184 | tlvtmp, err := iih.base.Tlv(TLV_CODE_AREA_ADDRESSES) 185 | if tlv, ok := tlvtmp.(*areaAddressesTlv); ok { 186 | return tlv, err 187 | } 188 | return nil, err 189 | } 190 | 191 | func (iih *IihPdu) ClearAreaAddressesTlvs() error { 192 | return iih.base.ClearTlvs(TLV_CODE_AREA_ADDRESSES) 193 | } 194 | 195 | func (iih *IihPdu) AddIsNeighboursHelloTlv(tlv *isNeighboursHelloTlv) error { 196 | return iih.base.AddTlv(tlv) 197 | } 198 | 199 | func (iih *IihPdu) IsNeighboursHelloTlvs() ([]*isNeighboursHelloTlv, error) { 200 | tlvs := make([]*isNeighboursHelloTlv, 0) 201 | tlvstmp, err := iih.base.Tlvs(TLV_CODE_IS_NEIGHBOURS_HELLO) 202 | if err != nil { 203 | return nil, err 204 | } 205 | for _, tlvtmp := range tlvstmp { 206 | if tlv, ok := tlvtmp.(*isNeighboursHelloTlv); ok { 207 | tlvs = append(tlvs, tlv) 208 | } 209 | } 210 | return tlvs, nil 211 | } 212 | 213 | func (iih *IihPdu) ClearIsNeighboursHelloTlvs() error { 214 | return iih.base.ClearTlvs(TLV_CODE_IS_NEIGHBOURS_HELLO) 215 | } 216 | 217 | func (iih *IihPdu) AddPaddingTlv(tlv *paddingTlv) error { 218 | return iih.base.AddTlv(tlv) 219 | } 220 | 221 | func (iih *IihPdu) ClearAddPaddingTlvs() error { 222 | return iih.base.ClearTlvs(TLV_CODE_PADDING) 223 | } 224 | 225 | func (iih *IihPdu) SetAuthInfoTlv(tlv *authInfoTlv) error { 226 | return iih.base.SetTlv(tlv) 227 | } 228 | 229 | func (iih *IihPdu) AuthInfoTlv() (*authInfoTlv, error) { 230 | tlvtmp, err := iih.base.Tlv(TLV_CODE_AUTH_INFO) 231 | if tlv, ok := tlvtmp.(*authInfoTlv); ok { 232 | return tlv, err 233 | } 234 | return nil, err 235 | } 236 | 237 | func (iih *IihPdu) ClearAuthInfoTlvs() error { 238 | return iih.base.ClearTlvs(TLV_CODE_AUTH_INFO) 239 | } 240 | 241 | func (iih *IihPdu) SetProtocolsSupportedTlv(tlv *protocolsSupportedTlv) error { 242 | return iih.base.SetTlv(tlv) 243 | } 244 | 245 | func (iih *IihPdu) ProtocolsSupportedTlv() (*protocolsSupportedTlv, error) { 246 | tlvtmp, err := iih.base.Tlv(TLV_CODE_PROTOCOLS_SUPPORTED) 247 | if tlv, ok := tlvtmp.(*protocolsSupportedTlv); ok { 248 | return tlv, err 249 | } 250 | return nil, err 251 | } 252 | 253 | func (iih *IihPdu) ClearProtocolsSupportedTlvs() error { 254 | return iih.base.ClearTlvs(TLV_CODE_PROTOCOLS_SUPPORTED) 255 | } 256 | 257 | func (iih *IihPdu) SetIpInterfaceAddressTlv(tlv *ipInterfaceAddressTlv) error { 258 | return iih.base.SetTlv(tlv) 259 | } 260 | 261 | func (iih *IihPdu) IpInterfaceAddressTlv() (*ipInterfaceAddressTlv, error) { 262 | tlvtmp, err := iih.base.Tlv(TLV_CODE_IP_INTERFACE_ADDRESS) 263 | if tlv, ok := tlvtmp.(*ipInterfaceAddressTlv); ok { 264 | return tlv, err 265 | } 266 | return nil, err 267 | } 268 | 269 | func (iih *IihPdu) ClearIpInterfaceAddressTlvs() error { 270 | return iih.base.ClearTlvs(TLV_CODE_IP_INTERFACE_ADDRESS) 271 | } 272 | 273 | func (iih *IihPdu) SetP2p3wayAdjacencyTlv(tlv *p2p3wayAdjacencyTlv) error { 274 | return iih.base.SetTlv(tlv) 275 | } 276 | 277 | func (iih *IihPdu) P2p3wayAdjacencyTlv() (*p2p3wayAdjacencyTlv, error) { 278 | tlvtmp, err := iih.base.Tlv(TLV_CODE_P2P_3WAY_ADJ) 279 | if tlv, ok := tlvtmp.(*p2p3wayAdjacencyTlv); ok { 280 | return tlv, err 281 | } 282 | return nil, err 283 | } 284 | 285 | func (iih *IihPdu) ClearP2p3wayAdjacencyTlvs() error { 286 | return iih.base.ClearTlvs(TLV_CODE_P2P_3WAY_ADJ) 287 | } 288 | 289 | func (iih *IihPdu) SetIpv6InterfaceAddressTlv(tlv *ipv6InterfaceAddressTlv) error { 290 | return iih.base.SetTlv(tlv) 291 | } 292 | 293 | func (iih *IihPdu) Ipv6InterfaceAddressTlv() (*ipv6InterfaceAddressTlv, error) { 294 | tlvtmp, err := iih.base.Tlv(TLV_CODE_IPV6_INTERFACE_ADDRESS) 295 | if tlv, ok := tlvtmp.(*ipv6InterfaceAddressTlv); ok { 296 | return tlv, err 297 | } 298 | return nil, err 299 | } 300 | 301 | func (iih *IihPdu) ClearIpv6InterfaceAddressTlvs() error { 302 | return iih.base.ClearTlvs(TLV_CODE_IPV6_INTERFACE_ADDRESS) 303 | } 304 | -------------------------------------------------------------------------------- /pkg/isis/packet/pdu_hello_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "encoding/binary" 23 | "testing" 24 | ) 25 | 26 | func TestIihPduP2pDecode(t *testing.T) { 27 | var err error 28 | 29 | d1 := []byte{ 30 | 0x83, 0x14, 0x01, 0x00, 0x11, 0x01, 0x00, 0x00, 0x02, 0x36, 0xd3, 0x64, 0x2f, 0x27, 0xad, 0x00, 0x1e, 0x05, 0xd9, 0x00, 31 | 0x81, 0x02, 0xcc, 0x8e, 32 | 0x01, 0x02, 0x01, 0x01, 33 | 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xa5, 0x6c, 0xc9, 0xad, 0xad, 0x00, 0x00, 0x00, 0x00, 34 | 0x84, 0x04, 0xc0, 0xa8, 0x0c, 0x01, 35 | 0xe8, 0x10, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x19, 0x81, 0xff, 0xfe, 0xa4, 0xbf, 0xd8, 36 | 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0xff, 0x02, 0x01, 0x02, 38 | } 39 | binary.BigEndian.PutUint16(d1[17:19], uint16(len(d1))) 40 | 41 | p1, err := DecodePduFromBytes(d1) 42 | if err != nil { 43 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 44 | } 45 | 46 | d2, err := p1.Serialize() 47 | if err != nil { 48 | t.Fatalf("failed Serialize: %#v", err) 49 | } 50 | 51 | if !bytes.Equal(d1, d2) { 52 | t.Fatalf("failed !bytes.Equal") 53 | } 54 | 55 | //t.Fatalf("\n%s", p1.String()) 56 | } 57 | 58 | func TestIihPduP2pNew(t *testing.T) { 59 | var err error 60 | 61 | p1, err := NewIihPdu(PDU_TYPE_P2P_IIHP) 62 | if err != nil { 63 | t.Fatalf("failed NewIihPdu: %#v", err) 64 | } 65 | 66 | tt, err := NewP2p3wayAdjacencyTlv() 67 | if err != nil { 68 | t.Fatalf("failed NewP2p3wayAdjacencyTlv: %#v", err) 69 | } 70 | tt.Adj3wayState = ADJ_3WAY_STATE_INITIALIZING 71 | xx := [SYSTEM_ID_LENGTH]byte{0x01, 0x01, 0x01, 0x02, 0x02, 0x02} 72 | tt.SetNeighbourSystemId(xx) 73 | p1.SetP2p3wayAdjacencyTlv(tt) 74 | 75 | //p1.ClearP2p3wayAdjacencyTlvs() 76 | 77 | tt2, err := NewPaddingTlv() 78 | if err != nil { 79 | t.Fatalf("failed NewPaddingTlv: %#v", err) 80 | } 81 | tt2.SetLength(8) 82 | p1.AddPaddingTlv(tt2) 83 | p1.AddPaddingTlv(tt2) 84 | 85 | d1, err := p1.Serialize() 86 | if err != nil { 87 | t.Fatalf("failed Serialize: %#v", err) 88 | } 89 | 90 | p2, err := DecodePduFromBytes(d1) 91 | if err != nil { 92 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 93 | } 94 | 95 | d2, err := p2.Serialize() 96 | if err != nil { 97 | t.Fatalf("failed Serialize: %#v", err) 98 | } 99 | 100 | if !bytes.Equal(d1, d2) { 101 | t.Fatalf("failed !bytes.Equal") 102 | } 103 | 104 | //t.Fatalf("\n%s", p1.String()) 105 | } 106 | 107 | func TestIihPduLan2Decode(t *testing.T) { 108 | var err error 109 | 110 | d1 := []byte{ 111 | 0x83, 0x1b, 0x01, 0x00, 0x10, 0x01, 0x00, 0x00, 0x02, 0x36, 0xd3, 0x64, 0x2f, 0x27, 0xad, 0x00, 0x1e, 0x05, 0xd9, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 112 | 0x81, 0x02, 0xcc, 0x8e, 113 | 0x01, 0x02, 0x01, 0x01, 114 | 0x84, 0x04, 0xc0, 0xa8, 0x0c, 0x01, 115 | 0xe8, 0x10, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0e, 0x6c, 0xff, 0xfe, 0x0c, 0xef, 0xba, 116 | 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 117 | 0xff, 0x02, 0x01, 0x02, 118 | } 119 | binary.BigEndian.PutUint16(d1[17:19], uint16(len(d1))) 120 | 121 | p1, err := DecodePduFromBytes(d1) 122 | if err != nil { 123 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 124 | } 125 | 126 | d2, err := p1.Serialize() 127 | if err != nil { 128 | t.Fatalf("failed Serialize: %#v", err) 129 | } 130 | 131 | if !bytes.Equal(d1, d2) { 132 | t.Fatalf("failed !bytes.Equal") 133 | } 134 | 135 | //t.Fatalf("\n%s", p1.String()) 136 | } 137 | 138 | func TestIihPduLan2New(t *testing.T) { 139 | var err error 140 | 141 | p1, err := NewIihPdu(PDU_TYPE_LEVEL2_LAN_IIHP) 142 | if err != nil { 143 | t.Fatalf("failed NewIihPdu: %#v", err) 144 | } 145 | 146 | d1, err := p1.Serialize() 147 | if err != nil { 148 | t.Fatalf("failed Serialize: %#v", err) 149 | } 150 | 151 | p2, err := DecodePduFromBytes(d1) 152 | if err != nil { 153 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 154 | } 155 | 156 | d2, err := p2.Serialize() 157 | if err != nil { 158 | t.Fatalf("failed Serialize: %#v", err) 159 | } 160 | 161 | if !bytes.Equal(d1, d2) { 162 | t.Fatalf("failed !bytes.Equal") 163 | } 164 | 165 | //t.Fatalf("\n%s", p1.String()) 166 | } 167 | -------------------------------------------------------------------------------- /pkg/isis/packet/pdu_linkstate_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | _ "encoding/binary" 23 | "testing" 24 | ) 25 | 26 | func TestLsPduDecode(t *testing.T) { 27 | var err error 28 | 29 | d1 := []byte{ 30 | 0x83, 0x1b, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x97, 0x04, 0x8b, 0x8e, 0x7f, 0x0f, 0x71, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xc5, 0x13, 0x03, 31 | 0x81, 0x02, 0xcc, 0x8e, 32 | 0x01, 0x02, 0x01, 0x01, 33 | 0x89, 0x08, 0x66, 0x72, 0x72, 0x74, 0x65, 0x73, 0x74, 0x33, 34 | 0x86, 0x04, 0xc0, 0xa8, 0x03, 0x01, 35 | 0x16, 0x16, 0x36, 0xd3, 0x64, 0x2f, 0x27, 0xad, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x12, 0x16, 0xbb, 0x16, 0xa8, 0xe9, 0x00, 0x00, 0x00, 0x0a, 0x00, 36 | 0x84, 0x04, 0xc0, 0xa8, 0x03, 0x01, 37 | 0x87, 0x18, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xc0, 0xa8, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xc0, 0xa8, 0x22, 0x00, 0x00, 0x00, 0x0a, 0x18, 0xc0, 0xa8, 0x03, 38 | 0xec, 0x2a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x03, 39 | } 40 | //binary.BigEndian.PutUint16(d1[8:10], uint16(len(d1))) 41 | 42 | p1, err := DecodePduFromBytes(d1) 43 | if err != nil { 44 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 45 | } 46 | 47 | d2, err := p1.Serialize() 48 | if err != nil { 49 | t.Fatalf("failed Serialize: %#v", err) 50 | } 51 | 52 | if !bytes.Equal(d1, d2) { 53 | t.Fatalf("failed !bytes.Equal") 54 | } 55 | 56 | //t.Fatalf("\n%s", p1.String()) 57 | } 58 | 59 | func TestLsPduNew(t *testing.T) { 60 | var err error 61 | 62 | p1, err := NewLsPdu(PDU_TYPE_LEVEL2_LSP) 63 | if err != nil { 64 | t.Fatalf("failed NewLsPdu: %#v", err) 65 | } 66 | 67 | d1, err := p1.Serialize() 68 | if err != nil { 69 | t.Fatalf("failed Serialize: %#v", err) 70 | } 71 | 72 | p2, err := DecodePduFromBytes(d1) 73 | if err != nil { 74 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 75 | } 76 | 77 | d2, err := p2.Serialize() 78 | if err != nil { 79 | t.Fatalf("failed Serialize: %#v", err) 80 | } 81 | 82 | if !bytes.Equal(d1, d2) { 83 | t.Fatalf("failed !bytes.Equal") 84 | } 85 | 86 | //t.Fatalf("\n%s", p1.String()) 87 | } 88 | -------------------------------------------------------------------------------- /pkg/isis/packet/pdu_seqnum.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "errors" 23 | "fmt" 24 | ) 25 | 26 | type SnPdu struct { 27 | base pduBase 28 | 29 | sourceId [NEIGHBOUR_ID_LENGTH]byte 30 | startLspId [LSP_ID_LENGTH]byte // CSN 31 | endLspId [LSP_ID_LENGTH]byte // CSN 32 | } 33 | 34 | func NewSnPdu(pduType PduType) (*SnPdu, error) { 35 | if pduType != PDU_TYPE_LEVEL1_CSNP && 36 | pduType != PDU_TYPE_LEVEL2_CSNP && 37 | pduType != PDU_TYPE_LEVEL1_PSNP && 38 | pduType != PDU_TYPE_LEVEL2_PSNP { 39 | return nil, errors.New("NewSnPdu: pduType invalid") 40 | } 41 | var lengthIndicator uint8 42 | switch pduType { 43 | case PDU_TYPE_LEVEL1_CSNP, PDU_TYPE_LEVEL2_CSNP: 44 | lengthIndicator = 15 + SYSTEM_ID_LENGTH*3 45 | case PDU_TYPE_LEVEL1_PSNP, PDU_TYPE_LEVEL2_PSNP: 46 | lengthIndicator = 11 + SYSTEM_ID_LENGTH 47 | } 48 | sn := SnPdu{ 49 | base: pduBase{ 50 | lengthIndicator: lengthIndicator, 51 | pduType: pduType, 52 | }, 53 | } 54 | sn.base.init() 55 | return &sn, nil 56 | } 57 | 58 | func (sn *SnPdu) PduType() PduType { 59 | return sn.base.pduType 60 | } 61 | 62 | func (sn *SnPdu) String() string { 63 | var b bytes.Buffer 64 | b.WriteString(sn.base.StringFixed()) 65 | fmt.Fprintf(&b, "sourceId ") 66 | for t := range sn.sourceId { 67 | fmt.Fprintf(&b, "%02x", t) 68 | } 69 | fmt.Fprintf(&b, "\n") 70 | if sn.base.pduType == PDU_TYPE_LEVEL1_CSNP || 71 | sn.base.pduType == PDU_TYPE_LEVEL2_CSNP { 72 | fmt.Fprintf(&b, "startLspId ") 73 | for t := range sn.startLspId { 74 | fmt.Fprintf(&b, "%02x", t) 75 | } 76 | fmt.Fprintf(&b, "\n") 77 | fmt.Fprintf(&b, "endLspId ") 78 | for t := range sn.endLspId { 79 | fmt.Fprintf(&b, "%02x", t) 80 | } 81 | fmt.Fprintf(&b, "\n") 82 | } 83 | b.WriteString(sn.base.StringTlv()) 84 | return b.String() 85 | } 86 | 87 | func (sn *SnPdu) DecodeFromBytes(data []byte) error { 88 | err := sn.base.DecodeFromBytes(data) 89 | if err != nil { 90 | return err 91 | } 92 | // 93 | // SourceId 94 | copy(sn.sourceId[0:NEIGHBOUR_ID_LENGTH], data[10:10+NEIGHBOUR_ID_LENGTH]) 95 | if sn.base.pduType == PDU_TYPE_LEVEL1_CSNP || 96 | sn.base.pduType == PDU_TYPE_LEVEL2_CSNP { 97 | // 98 | // StartLspId 99 | copy(sn.startLspId[0:LSP_ID_LENGTH], 100 | data[10+NEIGHBOUR_ID_LENGTH:10+NEIGHBOUR_ID_LENGTH+LSP_ID_LENGTH]) 101 | // 102 | // EndLspId 103 | copy(sn.endLspId[0:LSP_ID_LENGTH], 104 | data[10+NEIGHBOUR_ID_LENGTH+LSP_ID_LENGTH:10+NEIGHBOUR_ID_LENGTH+LSP_ID_LENGTH*2]) 105 | } 106 | return nil 107 | } 108 | 109 | func (sn *SnPdu) Serialize() ([]byte, error) { 110 | data, err := sn.base.Serialize() 111 | if err != nil { 112 | return data, err 113 | } 114 | // 115 | // SourceId 116 | copy(data[10:10+NEIGHBOUR_ID_LENGTH], sn.sourceId[0:NEIGHBOUR_ID_LENGTH]) 117 | if sn.base.pduType == PDU_TYPE_LEVEL1_CSNP || 118 | sn.base.pduType == PDU_TYPE_LEVEL2_CSNP { 119 | // 120 | // StartLspId 121 | copy(data[10+NEIGHBOUR_ID_LENGTH:10+NEIGHBOUR_ID_LENGTH+LSP_ID_LENGTH], 122 | sn.startLspId[0:LSP_ID_LENGTH]) 123 | // 124 | // EndLspId 125 | copy(data[10+NEIGHBOUR_ID_LENGTH+LSP_ID_LENGTH:10+NEIGHBOUR_ID_LENGTH+LSP_ID_LENGTH*2], 126 | sn.endLspId[0:LSP_ID_LENGTH]) 127 | } 128 | return data, nil 129 | } 130 | 131 | func (sn *SnPdu) BaseValid() bool { 132 | return sn.base.valid() 133 | } 134 | 135 | func (sn *SnPdu) SourceId() [NEIGHBOUR_ID_LENGTH]byte { 136 | return sn.sourceId 137 | } 138 | 139 | func (sn *SnPdu) SetSourceId(sourceId [NEIGHBOUR_ID_LENGTH]byte) error { 140 | sn.sourceId = sourceId 141 | return nil 142 | } 143 | 144 | func (sn *SnPdu) SetStartLspId(startLspId [LSP_ID_LENGTH]byte) error { 145 | sn.startLspId = startLspId 146 | return nil 147 | } 148 | 149 | func (sn *SnPdu) SetEndLspId(endLspId [LSP_ID_LENGTH]byte) error { 150 | sn.endLspId = endLspId 151 | return nil 152 | } 153 | 154 | func (sn *SnPdu) AddLspEntriesTlv(tlv *lspEntriesTlv) error { 155 | return sn.base.AddTlv(tlv) 156 | } 157 | 158 | func (sn *SnPdu) LspEntriesTlvs() ([]*lspEntriesTlv, error) { 159 | tlvs := make([]*lspEntriesTlv, 0) 160 | tlvstmp, err := sn.base.Tlvs(TLV_CODE_LSP_ENTRIES) 161 | if err != nil { 162 | return nil, err 163 | } 164 | for _, tlvtmp := range tlvstmp { 165 | if tlv, ok := tlvtmp.(*lspEntriesTlv); ok { 166 | tlvs = append(tlvs, tlv) 167 | } 168 | } 169 | return tlvs, nil 170 | } 171 | 172 | func (sn *SnPdu) ClearLspEntriesTlvs() error { 173 | return sn.base.ClearTlvs(TLV_CODE_LSP_ENTRIES) 174 | } 175 | 176 | func (sn *SnPdu) SetAuthInfoTlv(tlv *authInfoTlv) error { 177 | return sn.base.SetTlv(tlv) 178 | } 179 | 180 | func (sn *SnPdu) AuthInfoTlv() (*authInfoTlv, error) { 181 | tlvtmp, err := sn.base.Tlv(TLV_CODE_AUTH_INFO) 182 | if tlv, ok := tlvtmp.(*authInfoTlv); ok { 183 | return tlv, err 184 | } 185 | return nil, err 186 | } 187 | 188 | func (sn *SnPdu) ClearAuthInfoTlvs() error { 189 | return sn.base.ClearTlvs(TLV_CODE_AUTH_INFO) 190 | } 191 | -------------------------------------------------------------------------------- /pkg/isis/packet/pdu_seqnum_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | _ "encoding/binary" 23 | "testing" 24 | ) 25 | 26 | func TestSnPduCsnpDecode(t *testing.T) { 27 | var err error 28 | 29 | d1 := []byte{ 30 | 0x83, 0x21, 0x01, 0x00, 0x19, 0x01, 0x00, 0x00, 0x00, 0x73, 0xfa, 0xa5, 0x6c, 0xc9, 0xad, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 31 | 0x09, 0x50, 32 | 0x04, 0x5e, 0x12, 0x16, 0xbb, 0x16, 0xa8, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa4, 0x9b, 33 | 0x04, 0x66, 0x36, 0xd3, 0x64, 0x2f, 0x27, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0b, 0xab, 34 | 0x04, 0x75, 0x8e, 0x7f, 0x0f, 0x71, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe8, 0x78, 35 | 0x04, 0x8f, 0xfa, 0xa5, 0x6c, 0xc9, 0xad, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xeb, 0xe9, 36 | 0x04, 0x7f, 0xfa, 0xa5, 0x6c, 0xc9, 0xad, 0xad, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x02, 0x16, 0x1d, 37 | } 38 | //binary.BigEndian.PutUint16(d1[8:10], uint16(len(d1))) 39 | 40 | p1, err := DecodePduFromBytes(d1) 41 | if err != nil { 42 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 43 | } 44 | 45 | d2, err := p1.Serialize() 46 | if err != nil { 47 | t.Fatalf("failed Serialize: %#v", err) 48 | } 49 | 50 | if !bytes.Equal(d1, d2) { 51 | t.Fatalf("failed !bytes.Equal") 52 | } 53 | 54 | //t.Fatalf("\n%s", p1.String()) 55 | } 56 | 57 | func TestSnPduCsnpNew(t *testing.T) { 58 | var err error 59 | 60 | p1, err := NewSnPdu(PDU_TYPE_LEVEL2_CSNP) 61 | if err != nil { 62 | t.Fatalf("failed NewSnPdu: %#v", err) 63 | } 64 | 65 | d1, err := p1.Serialize() 66 | if err != nil { 67 | t.Fatalf("failed Serialize: %#v", err) 68 | } 69 | 70 | p2, err := DecodePduFromBytes(d1) 71 | if err != nil { 72 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 73 | } 74 | 75 | d2, err := p2.Serialize() 76 | if err != nil { 77 | t.Fatalf("failed Serialize: %#v", err) 78 | } 79 | 80 | if !bytes.Equal(d1, d2) { 81 | t.Fatalf("failed !bytes.Equal") 82 | } 83 | 84 | //t.Fatalf("\n%s", p1.String()) 85 | } 86 | 87 | func TestSnPduPsnpDecode(t *testing.T) { 88 | var err error 89 | 90 | d1 := []byte{ 91 | 0x83, 0x11, 0x01, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x23, 0x36, 0xd3, 0x64, 0x2f, 0x27, 0xad, 0x00, 92 | 0x09, 0x10, 93 | 0x04, 0x8d, 0xfa, 0xa5, 0x6c, 0xc9, 0xad, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3a, 0xb8, 94 | } 95 | //binary.BigEndian.PutUint16(d1[8:10], uint16(len(d1))) 96 | 97 | p1, err := DecodePduFromBytes(d1) 98 | if err != nil { 99 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 100 | } 101 | 102 | d2, err := p1.Serialize() 103 | if err != nil { 104 | t.Fatalf("failed Serialize: %#v", err) 105 | } 106 | 107 | if !bytes.Equal(d1, d2) { 108 | t.Fatalf("failed !bytes.Equal") 109 | } 110 | 111 | //t.Fatalf("\n%s", p1.String()) 112 | } 113 | 114 | func TestSnPduPsnpNew(t *testing.T) { 115 | var err error 116 | 117 | p1, err := NewSnPdu(PDU_TYPE_LEVEL2_PSNP) 118 | if err != nil { 119 | t.Fatalf("failed NewSnPdu: %#v", err) 120 | } 121 | 122 | d1, err := p1.Serialize() 123 | if err != nil { 124 | t.Fatalf("failed Serialize: %#v", err) 125 | } 126 | 127 | p2, err := DecodePduFromBytes(d1) 128 | if err != nil { 129 | t.Fatalf("failed DecodePduFromBytes: %#v", err) 130 | } 131 | 132 | d2, err := p2.Serialize() 133 | if err != nil { 134 | t.Fatalf("failed Serialize: %#v", err) 135 | } 136 | 137 | if !bytes.Equal(d1, d2) { 138 | t.Fatalf("failed !bytes.Equal") 139 | } 140 | 141 | //t.Fatalf("\n%s", p1.String()) 142 | } 143 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_base.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "errors" 23 | "fmt" 24 | ) 25 | 26 | type tlvBase struct { 27 | code TlvCode 28 | length uint8 29 | value []byte 30 | } 31 | 32 | func (base *tlvBase) init() { 33 | base.value = make([]byte, 0) 34 | } 35 | 36 | func (base *tlvBase) String() string { 37 | var b bytes.Buffer 38 | fmt.Fprintf(&b, " code %s(%d)\n", base.code.String(), base.code) 39 | fmt.Fprintf(&b, " Length %d\n", base.length) 40 | fmt.Fprintf(&b, " Value ") 41 | for i := 0; i < len(base.value); i++ { 42 | if i > 0 && i%20 == 0 { 43 | fmt.Fprintf(&b, "\n ") 44 | } 45 | fmt.Fprintf(&b, "%02x", base.value[i]) 46 | } 47 | fmt.Fprintf(&b, "\n") 48 | return b.String() 49 | } 50 | 51 | func (base *tlvBase) DecodeFromBytes(data []byte) error { 52 | if len(data) < 2 { 53 | return errors.New("tlvBase.DecodeFromBytes: data length too short") 54 | } 55 | base.code = TlvCode(data[0]) 56 | base.length = data[1] 57 | if len(data) != int(base.length)+2 { 58 | s := fmt.Sprintf("tlvBase.DecodeFromBytes: data length mismatch %d %d %d", 59 | uint8(data[0]), len(data), int(base.length)+2) 60 | return errors.New(s) 61 | } 62 | base.value = make([]byte, len(data)-2) 63 | copy(base.value, data[2:]) 64 | return nil 65 | } 66 | 67 | func (base *tlvBase) Serialize() ([]byte, error) { 68 | if len(base.value) != int(base.length) { 69 | return nil, errors.New("tlvBase.Serialize: value length mismatch") 70 | } 71 | data := make([]byte, int(base.length)+2) 72 | data[0] = uint8(base.code) 73 | data[1] = base.length 74 | copy(data[2:], base.value) 75 | return data, nil 76 | } 77 | 78 | func DecodeTlvFromBytes(data []byte) (IsisTlv, error) { 79 | var tlv IsisTlv 80 | var err error 81 | if len(data) < 2 { 82 | return nil, errors.New("DecodeTlvFromBytes: data length too short") 83 | } 84 | code := TlvCode(data[0]) 85 | switch code { 86 | case TLV_CODE_AREA_ADDRESSES: 87 | tlv, err = NewAreaAddressesTlv() 88 | case TLV_CODE_IS_NEIGHBOURS_LSP: 89 | tlv, err = NewIsNeighboursLspTlv() 90 | /* 91 | case TLV_CODE_ES_NEIGHBOURS: 92 | tlv, err = NewEsNeighboursTlv() 93 | */ 94 | case TLV_CODE_PARTITION_DESIGNATED_L2_IS: 95 | tlv, err = NewPartitionDesignatedL2IsTlv() 96 | /* 97 | case TLV_CODE_PREFIX_NEIGHBOURS: 98 | tlv, err = NewPrefixNeighboursTlv() 99 | */ 100 | case TLV_CODE_IS_NEIGHBOURS_HELLO: 101 | tlv, err = NewIsNeighboursHelloTlv() 102 | /* 103 | case TLV_CODE_IS_NEIGHBOURS_VARIABLE: 104 | tlv, err = NewIsNeighboursVariableTlv() 105 | */ 106 | case TLV_CODE_PADDING: 107 | tlv, err = NewPaddingTlv() 108 | case TLV_CODE_LSP_ENTRIES: 109 | tlv, err = NewLspEntriesTlv() 110 | case TLV_CODE_AUTH_INFO: 111 | tlv, err = NewAuthInfoTlv() 112 | case TLV_CODE_LSP_BUFF_SIZE: 113 | tlv, err = NewLspBuffSizeTlv() 114 | default: 115 | tlv, err = NewUnknownTlv(code) 116 | } 117 | if err != nil { 118 | return nil, err 119 | } 120 | err = tlv.DecodeFromBytes(data) 121 | if err != nil { 122 | return nil, err 123 | } 124 | return tlv, nil 125 | } 126 | 127 | type unknownTlv struct { 128 | base tlvBase 129 | } 130 | 131 | func NewUnknownTlv(code TlvCode) (*unknownTlv, error) { 132 | tlv := unknownTlv{ 133 | base: tlvBase{ 134 | code: code, 135 | }, 136 | } 137 | tlv.base.init() 138 | return &tlv, nil 139 | } 140 | 141 | func (tlv *unknownTlv) TlvCode() TlvCode { 142 | return tlv.base.code 143 | } 144 | 145 | func (tlv *unknownTlv) String() string { 146 | var b bytes.Buffer 147 | b.WriteString(tlv.base.String()) 148 | return b.String() 149 | } 150 | 151 | func (tlv *unknownTlv) DecodeFromBytes(data []byte) error { 152 | err := tlv.base.DecodeFromBytes(data) 153 | if err != nil { 154 | return err 155 | } 156 | return nil 157 | } 158 | 159 | func (tlv *unknownTlv) Serialize() ([]byte, error) { 160 | data, err := tlv.base.Serialize() 161 | if err != nil { 162 | return data, err 163 | } 164 | return data, nil 165 | } 166 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_iso10589_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "testing" 23 | ) 24 | 25 | func TestAreaAddressesTlv(t *testing.T) { 26 | var err error 27 | p1 := []byte{0x01, 0x08, 0x02, 0x0a, 0x0b, 0x04, 0x01, 0x02, 0x03, 0x04} 28 | 29 | t1, err := NewAreaAddressesTlv() 30 | if err != nil { 31 | t.Fatalf("failed NewAreaAddressesTlv: %#v", err) 32 | } 33 | 34 | err = t1.DecodeFromBytes(p1) 35 | if err != nil { 36 | t.Fatalf("failed DecodeFromBytes: %#v", err) 37 | } 38 | 39 | p2, err := t1.Serialize() 40 | if err != nil { 41 | t.Fatalf("failed Serialize: %#v", err) 42 | } 43 | 44 | if !bytes.Equal(p1, p2) { 45 | t.Fatalf("failed !Equal") 46 | } 47 | 48 | err = t1.AddAreaAddress([]byte{0xaa, 0xbb}) 49 | if err != nil { 50 | t.Fatalf("failed AddAreaAddress: %#v", err) 51 | } 52 | 53 | p3, err := t1.Serialize() 54 | if err != nil { 55 | t.Fatalf("failed Serialize: %#v", err) 56 | } 57 | 58 | if bytes.Equal(p1, p3) { 59 | t.Fatalf("failed Equal") 60 | } 61 | 62 | err = t1.RemoveAreaAddress([]byte{0xaa, 0xbb}) 63 | if err != nil { 64 | t.Fatalf("failed RemoveAddress: %#v", err) 65 | } 66 | 67 | p4, err := t1.Serialize() 68 | if err != nil { 69 | t.Fatalf("failed Serialize: %#v", err) 70 | } 71 | 72 | if !bytes.Equal(p1, p4) { 73 | t.Fatalf("failed !Equal") 74 | } 75 | } 76 | 77 | func TestIsNeighboursLspTlv(t *testing.T) { 78 | var err error 79 | p1 := []byte{0x02, 0x17, 0x00, 80 | 0x0a, 0x80, 0x80, 0x80, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 81 | 0x0a, 0x80, 0x80, 0x80, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 82 | } 83 | 84 | t1, err := NewIsNeighboursLspTlv() 85 | if err != nil { 86 | t.Fatalf("failed NewIsNeighboursLspTlv: %#v", err) 87 | } 88 | 89 | err = t1.DecodeFromBytes(p1) 90 | if err != nil { 91 | t.Fatalf("failed DecodeFromBytes: %#v", err) 92 | } 93 | 94 | p2, err := t1.Serialize() 95 | if err != nil { 96 | t.Fatalf("failed Serialize: %#v", err) 97 | } 98 | 99 | if !bytes.Equal(p1, p2) { 100 | t.Fatalf("failed !Equal") 101 | } 102 | 103 | n1, err := NewIsNeighboursLspNeighbour([NEIGHBOUR_ID_LENGTH]byte{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}) 104 | if err != nil { 105 | t.Fatalf("failed NewIsNeighboursLspNeighbour: %#v", err) 106 | } 107 | 108 | n1.DefaultMetric = 20 109 | err = t1.AddNeighbour(n1) 110 | if err != nil { 111 | t.Fatalf("failed AddNeighbour: %#v", err) 112 | } 113 | 114 | p3, err := t1.Serialize() 115 | if err != nil { 116 | t.Fatalf("failed Serialize: %#v", err) 117 | } 118 | 119 | if bytes.Equal(p1, p3) { 120 | t.Fatalf("failed !Equal") 121 | } 122 | 123 | err = t1.RemoveNeighbour([NEIGHBOUR_ID_LENGTH]byte{0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}) 124 | if err != nil { 125 | t.Fatalf("failed RemoveNeighbour: %#v", err) 126 | } 127 | 128 | p4, err := t1.Serialize() 129 | if err != nil { 130 | t.Fatalf("failed Serialize: %#v", err) 131 | } 132 | if !bytes.Equal(p1, p4) { 133 | t.Fatalf("failed !Equal") 134 | } 135 | 136 | t1.VirtualFlag = true 137 | p5, err := t1.Serialize() 138 | if err != nil { 139 | t.Fatalf("failed Serialize: %#v", err) 140 | } 141 | if bytes.Equal(p1, p5) { 142 | t.Fatalf("failed !Equal") 143 | } 144 | 145 | t1.VirtualFlag = false 146 | p6, err := t1.Serialize() 147 | if err != nil { 148 | t.Fatalf("failed Serialize: %#v", err) 149 | } 150 | if !bytes.Equal(p1, p6) { 151 | t.Fatalf("failed !Equal") 152 | } 153 | 154 | n2, err := NewIsNeighboursLspNeighbour([NEIGHBOUR_ID_LENGTH]byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}) 155 | if err != nil { 156 | t.Fatalf("failed RemoveNeighbour: %#v", err) 157 | } 158 | 159 | n2.DefaultMetric = 20 160 | 161 | err = t1.RemoveNeighbour([NEIGHBOUR_ID_LENGTH]byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00}) 162 | if err != nil { 163 | t.Fatalf("failed RemoveNeighbour: %#v", err) 164 | } 165 | 166 | err = t1.AddNeighbour(n2) 167 | if err != nil { 168 | t.Fatalf("failed AddNeighbour: %#v", err) 169 | } 170 | 171 | p7, err := t1.Serialize() 172 | if err != nil { 173 | t.Fatalf("failed Serialize: %#v", err) 174 | } 175 | 176 | if bytes.Equal(p1, p7) { 177 | t.Fatalf("failed Equal: \n%x\n%x", p1, p7) 178 | } 179 | } 180 | 181 | func TestPartitionDesignatedL2IsTlv(t *testing.T) { 182 | var err error 183 | p1 := []byte{0x04, 0x06, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} 184 | 185 | t1, err := NewPartitionDesignatedL2IsTlv() 186 | if err != nil { 187 | t.Fatalf("failed NewPartitionDesignatedL2IsTlv: %#v", err) 188 | } 189 | 190 | err = t1.DecodeFromBytes(p1) 191 | if err != nil { 192 | t.Fatalf("failed DecodeFromBytes: %#v", err) 193 | } 194 | 195 | p2, err := t1.Serialize() 196 | if err != nil { 197 | t.Fatalf("failed Serialize: %#v", err) 198 | } 199 | 200 | if !bytes.Equal(p1, p2) { 201 | t.Fatalf("failed !Equal") 202 | } 203 | 204 | err = t1.SetDesignatedL2IsId([SYSTEM_ID_LENGTH]byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00}) 205 | if err != nil { 206 | t.Fatalf("failed SetDesignatedL2IsId: %#v", err) 207 | } 208 | 209 | p3, err := t1.Serialize() 210 | if err != nil { 211 | t.Fatalf("failed Serialize: %#v", err) 212 | } 213 | 214 | if bytes.Equal(p1, p3) { 215 | t.Fatalf("failed Equal") 216 | } 217 | } 218 | 219 | func TestIsNeighboursHelloTlv(t *testing.T) { 220 | var err error 221 | p1 := []byte{0x06, 0x0c, 222 | 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 223 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 224 | } 225 | 226 | t1, err := NewIsNeighboursHelloTlv() 227 | if err != nil { 228 | t.Fatalf("failed NewIsNeighboursHelloTlv: %#v", err) 229 | } 230 | 231 | err = t1.DecodeFromBytes(p1) 232 | if err != nil { 233 | t.Fatalf("failed DecodeFromBytes: %#v", err) 234 | } 235 | 236 | p2, err := t1.Serialize() 237 | if err != nil { 238 | t.Fatalf("failed Serialize: %#v", err) 239 | } 240 | 241 | if !bytes.Equal(p1, p2) { 242 | t.Fatalf("failed !Equal") 243 | } 244 | } 245 | 246 | func TestPaddingTlv(t *testing.T) { 247 | var err error 248 | p1 := []byte{0x08, 0x04, 0x00, 0x00, 0x00, 0x00} 249 | 250 | t1, err := NewPaddingTlv() 251 | if err != nil { 252 | t.Fatalf("failed NewPaddingTlv: %#v", err) 253 | } 254 | 255 | err = t1.DecodeFromBytes(p1) 256 | if err != nil { 257 | t.Fatalf("failed DecodeFromBytes: %#v", err) 258 | } 259 | 260 | p2, err := t1.Serialize() 261 | if err != nil { 262 | t.Fatalf("failed Serialize: %#v", err) 263 | } 264 | 265 | if !bytes.Equal(p1, p2) { 266 | t.Fatalf("failed !Equal") 267 | } 268 | 269 | t1.SetLength(10) 270 | 271 | p3, err := t1.Serialize() 272 | if err != nil { 273 | t.Fatalf("failed Serialize: %#v", err) 274 | } 275 | 276 | if len(p3) != 12 { 277 | t.Fatalf("failed len(p3) != 12") 278 | } 279 | } 280 | 281 | func TestLspEntriesTlv(t *testing.T) { 282 | var err error 283 | p1 := []byte{0x09, 0x10, 284 | 0x04, 0x8d, 0xfa, 0xa5, 0x6c, 0xc9, 0xad, 0xad, 285 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3a, 0xb8, 286 | } 287 | 288 | t1, err := NewLspEntriesTlv() 289 | if err != nil { 290 | t.Fatalf("failed NewLspEntriesTlv: %#v", err) 291 | } 292 | 293 | err = t1.DecodeFromBytes(p1) 294 | if err != nil { 295 | t.Fatalf("failed DecodeFromBytes: %#v", err) 296 | } 297 | 298 | p2, err := t1.Serialize() 299 | if err != nil { 300 | t.Fatalf("failed Serialize: %#v", err) 301 | } 302 | 303 | if !bytes.Equal(p1, p2) { 304 | t.Fatalf("failed !Equal:\n%x\n%x", p1, p2) 305 | } 306 | } 307 | 308 | func TestAuthInfoTlv(t *testing.T) { 309 | var err error 310 | p1 := []byte{0x0a, 0x09, 311 | 0x01, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} 312 | 313 | t1, err := NewAuthInfoTlv() 314 | if err != nil { 315 | t.Fatalf("failed NewAuthInfoTlv: %#v", err) 316 | } 317 | 318 | err = t1.DecodeFromBytes(p1) 319 | if err != nil { 320 | t.Fatalf("failed DecodeFromBytes: %#v", err) 321 | } 322 | 323 | p2, err := t1.Serialize() 324 | if err != nil { 325 | t.Fatalf("failed Serialize: %#v", err) 326 | } 327 | 328 | if !bytes.Equal(p1, p2) { 329 | t.Fatalf("failed !Equal:\n%x\n%x", p1, p2) 330 | } 331 | } 332 | 333 | func TestLspBuffSizeTlv(t *testing.T) { 334 | var err error 335 | p1 := []byte{0x0e, 0x02, 0xd4, 0x05} 336 | 337 | t1, err := NewLspBuffSizeTlv() 338 | if err != nil { 339 | t.Fatalf("failed NewLspBuffSizeTlv: %#v", err) 340 | } 341 | 342 | err = t1.DecodeFromBytes(p1) 343 | if err != nil { 344 | t.Fatalf("failed DecodeFromBytes: %#v", err) 345 | } 346 | 347 | p2, err := t1.Serialize() 348 | if err != nil { 349 | t.Fatalf("failed Serialize: %#v", err) 350 | } 351 | 352 | if !bytes.Equal(p1, p2) { 353 | t.Fatalf("failed !Equal:\n%x\n%x", p1, p2) 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_rfc1195_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "testing" 23 | ) 24 | 25 | func TestIpInternalReachInfoTlv(t *testing.T) { 26 | var err error 27 | p1 := []byte{0x80, 0x18, 28 | 0x0a, 0x80, 0x80, 0x80, 0xc0, 0xa8, 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 29 | 0x0a, 0x80, 0x80, 0x80, 0xac, 0x10, 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 30 | } 31 | 32 | t1, err := NewIpInternalReachInfoTlv() 33 | if err != nil { 34 | t.Fatalf("failed NewIpInternalReachInfoTlv: %#v", err) 35 | } 36 | 37 | err = t1.DecodeFromBytes(p1) 38 | if err != nil { 39 | t.Fatalf("failed DecodeFromBytes: %#v", err) 40 | } 41 | 42 | p2, err := t1.Serialize() 43 | if err != nil { 44 | t.Fatalf("failed Serialize: %#v", err) 45 | } 46 | 47 | if !bytes.Equal(p1, p2) { 48 | t.Fatalf("failed !Equal") 49 | } 50 | } 51 | 52 | func TestProtocolsSupportedTlv(t *testing.T) { 53 | var err error 54 | p1 := []byte{0x81, 0x02, 0xcc, 0x8e} 55 | 56 | t1, err := NewProtocolsSupportedTlv() 57 | if err != nil { 58 | t.Fatalf("failed NewProtocolsSupportedTlv: %#v", err) 59 | } 60 | 61 | err = t1.DecodeFromBytes(p1) 62 | if err != nil { 63 | t.Fatalf("failed DecodeFromBytes: %#v", err) 64 | } 65 | 66 | p2, err := t1.Serialize() 67 | if err != nil { 68 | t.Fatalf("failed Serialize: %#v", err) 69 | } 70 | 71 | if !bytes.Equal(p1, p2) { 72 | t.Fatalf("failed !Equal") 73 | } 74 | } 75 | 76 | func TestIpExternalReachInfoTlv(t *testing.T) { 77 | var err error 78 | p1 := []byte{0x82, 0x18, 79 | 0x0a, 0x80, 0x80, 0x80, 0xc0, 0xa8, 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 80 | 0x0a, 0x80, 0x80, 0x80, 0xac, 0x10, 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 81 | } 82 | 83 | t1, err := NewIpExternalReachInfoTlv() 84 | if err != nil { 85 | t.Fatalf("failed NewIpExternalReachInfoTlv: %#v", err) 86 | } 87 | 88 | err = t1.DecodeFromBytes(p1) 89 | if err != nil { 90 | t.Fatalf("failed DecodeFromBytes: %#v", err) 91 | } 92 | 93 | p2, err := t1.Serialize() 94 | if err != nil { 95 | t.Fatalf("failed Serialize: %#v", err) 96 | } 97 | 98 | if !bytes.Equal(p1, p2) { 99 | t.Fatalf("failed !Equal") 100 | } 101 | } 102 | 103 | func TestInterDomainRoutingProtoInfoTlv(t *testing.T) { 104 | var err error 105 | p1 := []byte{0x83, 0x04, 0x01, 0x02, 0x03, 0x04} 106 | 107 | t1, err := NewInterDomainRoutingProtoInfoTlv() 108 | if err != nil { 109 | t.Fatalf("failed NewInterDomainRoutingProtoInfoTlv: %#v", err) 110 | } 111 | 112 | err = t1.DecodeFromBytes(p1) 113 | if err != nil { 114 | t.Fatalf("failed DecodeFromBytes: %#v", err) 115 | } 116 | 117 | p2, err := t1.Serialize() 118 | if err != nil { 119 | t.Fatalf("failed Serialize: %#v", err) 120 | } 121 | 122 | if !bytes.Equal(p1, p2) { 123 | t.Fatalf("failed !Equal") 124 | } 125 | } 126 | 127 | func TestIpInterfaceAddressTlv(t *testing.T) { 128 | var err error 129 | p1 := []byte{0x84, 0x08, 0xc0, 0xa8, 0x01, 0x01, 0xac, 0x10, 0x01, 0x01} 130 | 131 | t1, err := NewIpInterfaceAddressTlv() 132 | if err != nil { 133 | t.Fatalf("failed NewIpInterfaceAddressTlv: %#v", err) 134 | } 135 | 136 | err = t1.DecodeFromBytes(p1) 137 | if err != nil { 138 | t.Fatalf("failed DecodeFromBytes: %#v", err) 139 | } 140 | 141 | p2, err := t1.Serialize() 142 | if err != nil { 143 | t.Fatalf("failed Serialize: %#v", err) 144 | } 145 | 146 | if !bytes.Equal(p1, p2) { 147 | t.Fatalf("failed !Equal") 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_rfc5301.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "fmt" 23 | ) 24 | 25 | /* 26 | Dynamic hostname 27 | code - 137 28 | Length - 29 | Value - 30 | +------------------------+ 31 | | Dynamic Hostname | 32 | +------------------------+ 33 | */ 34 | 35 | type dynamicHostnameTlv struct { 36 | base tlvBase 37 | dynamicHostname []byte 38 | } 39 | 40 | func NewDynamicHostnameTlv() (*dynamicHostnameTlv, error) { 41 | tlv := dynamicHostnameTlv{ 42 | base: tlvBase{ 43 | code: TLV_CODE_DYNAMIC_HOSTNAME, 44 | }, 45 | } 46 | tlv.base.init() 47 | tlv.dynamicHostname = make([]byte, 0) 48 | return &tlv, nil 49 | } 50 | 51 | func (tlv *dynamicHostnameTlv) SetDynamicHostname(dynamicHostname []byte) error { 52 | dhtmp := make([]byte, len(dynamicHostname)) 53 | copy(dhtmp, dynamicHostname) 54 | tlv.dynamicHostname = dhtmp 55 | tlv.base.length = uint8(len(dhtmp)) 56 | return nil 57 | } 58 | 59 | func (tlv *dynamicHostnameTlv) TlvCode() TlvCode { 60 | return tlv.base.code 61 | } 62 | 63 | func (tlv *dynamicHostnameTlv) String() string { 64 | var b bytes.Buffer 65 | b.WriteString(tlv.base.String()) 66 | fmt.Fprintf(&b, " DynamicHostname ") 67 | for _, btmp := range tlv.dynamicHostname { 68 | fmt.Fprintf(&b, "%02x", btmp) 69 | } 70 | fmt.Fprintf(&b, "\n") 71 | return b.String() 72 | } 73 | 74 | func (tlv *dynamicHostnameTlv) DecodeFromBytes(data []byte) error { 75 | err := tlv.base.DecodeFromBytes(data) 76 | if err != nil { 77 | return err 78 | } 79 | dynamicHostname := make([]byte, len(tlv.base.value)) 80 | copy(dynamicHostname, tlv.base.value) 81 | tlv.dynamicHostname = dynamicHostname 82 | return nil 83 | } 84 | 85 | func (tlv *dynamicHostnameTlv) Serialize() ([]byte, error) { 86 | value := make([]byte, len(tlv.dynamicHostname)) 87 | copy(value, tlv.dynamicHostname) 88 | tlv.base.length = uint8(len(value)) 89 | tlv.base.value = value 90 | data, err := tlv.base.Serialize() 91 | if err != nil { 92 | return data, err 93 | } 94 | return data, nil 95 | } 96 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_rfc5301_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "testing" 23 | ) 24 | 25 | func TestDynamicHostnameTlv(t *testing.T) { 26 | var err error 27 | p1 := []byte{0x89, 0x04, 0x74, 0x65, 0x73, 0x74} 28 | 29 | t1, err := NewDynamicHostnameTlv() 30 | if err != nil { 31 | t.Fatalf("failed NewDynamicHostnameTlv: %#v", err) 32 | } 33 | 34 | err = t1.DecodeFromBytes(p1) 35 | if err != nil { 36 | t.Fatalf("failed DecodeFromBytes: %#v", err) 37 | } 38 | 39 | p2, err := t1.Serialize() 40 | if err != nil { 41 | t.Fatalf("failed Serialize: %#v", err) 42 | } 43 | 44 | if !bytes.Equal(p1, p2) { 45 | t.Fatalf("failed !Equal") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_rfc5303.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "encoding/binary" 23 | "errors" 24 | "fmt" 25 | ) 26 | 27 | /* 28 | Point-to-Point Three-Way Adjacency 29 | code - 240 30 | Length - 31 | Value - 32 | +------------------------+ 33 | | AdjacencyThreeWayState | 1 34 | +------------------------+ 35 | | ExtendedLocalCircuitID | 4 36 | +------------------------+ 37 | | Neighbour System ID | ID Length 38 | +------------------------+ 39 | | NeighExtLocalCircuitID | 4 40 | +------------------------+ 41 | */ 42 | 43 | type p2p3wayAdjacencyTlv struct { 44 | base tlvBase 45 | Adj3wayState Adj3wayState 46 | ExtLocalCircuitId uint32 47 | neighbourSystemId [SYSTEM_ID_LENGTH]byte 48 | NeighExtLocalCircuitId uint32 49 | } 50 | 51 | func NewP2p3wayAdjacencyTlv() (*p2p3wayAdjacencyTlv, error) { 52 | tlv := p2p3wayAdjacencyTlv{ 53 | base: tlvBase{ 54 | code: TLV_CODE_P2P_3WAY_ADJ, 55 | }, 56 | } 57 | tlv.base.init() 58 | return &tlv, nil 59 | } 60 | 61 | func (tlv *p2p3wayAdjacencyTlv) SetNeighbourSystemId(neighbourSystemId [SYSTEM_ID_LENGTH]byte) error { 62 | tlv.neighbourSystemId = neighbourSystemId 63 | tlv.base.length = 9 + SYSTEM_ID_LENGTH 64 | return nil 65 | } 66 | 67 | func (tlv *p2p3wayAdjacencyTlv) TlvCode() TlvCode { 68 | return tlv.base.code 69 | } 70 | 71 | func (tlv *p2p3wayAdjacencyTlv) String() string { 72 | var b bytes.Buffer 73 | b.WriteString(tlv.base.String()) 74 | fmt.Fprintf(&b, " AdjThreeWayState %s\n", tlv.Adj3wayState) 75 | fmt.Fprintf(&b, " ExtLocalCircuitID 0x%08x\n", tlv.ExtLocalCircuitId) 76 | fmt.Fprintf(&b, " NeighbourSystemID ") 77 | for _, btmp := range tlv.neighbourSystemId { 78 | fmt.Fprintf(&b, "%02x", btmp) 79 | } 80 | fmt.Fprintf(&b, "\n") 81 | fmt.Fprintf(&b, " NeighExtLocalCircID 0x%08x\n", tlv.NeighExtLocalCircuitId) 82 | return b.String() 83 | } 84 | 85 | func (tlv *p2p3wayAdjacencyTlv) DecodeFromBytes(data []byte) error { 86 | err := tlv.base.DecodeFromBytes(data) 87 | if err != nil { 88 | return err 89 | } 90 | tlv.Adj3wayState = Adj3wayState(tlv.base.value[0]) 91 | tlv.ExtLocalCircuitId = 0 92 | if len(tlv.base.value) > 1 { 93 | if len(tlv.base.value) < 5 { 94 | return errors.New("P2p3wayAdjacencyTlv.DecodeFromBytes: length invalid") 95 | } 96 | tlv.ExtLocalCircuitId = binary.BigEndian.Uint32(tlv.base.value[1:5]) 97 | } 98 | if len(tlv.base.value) > 5 { 99 | if len(tlv.base.value) < 5+SYSTEM_ID_LENGTH { 100 | return errors.New("P2p3wayAdjacencyTlv.DecodeFromBytes: length invalid") 101 | } 102 | copy(tlv.neighbourSystemId[0:SYSTEM_ID_LENGTH], tlv.base.value[5:5+SYSTEM_ID_LENGTH]) 103 | } 104 | tlv.NeighExtLocalCircuitId = 0 105 | if len(tlv.base.value) > 5+SYSTEM_ID_LENGTH { 106 | if len(tlv.base.value) < 9+SYSTEM_ID_LENGTH { 107 | return errors.New("P2p3wayAdjacencyTlv.DecodeFromBytes: length invalid") 108 | } 109 | tlv.NeighExtLocalCircuitId = binary.BigEndian.Uint32(tlv.base.value[5+SYSTEM_ID_LENGTH : 9+SYSTEM_ID_LENGTH]) 110 | } 111 | return nil 112 | } 113 | 114 | func (tlv *p2p3wayAdjacencyTlv) Serialize() ([]byte, error) { 115 | length := 5 116 | if tlv.Adj3wayState != ADJ_3WAY_STATE_DOWN { 117 | length = 9 + SYSTEM_ID_LENGTH 118 | } 119 | value := make([]byte, length) 120 | value[0] = uint8(tlv.Adj3wayState) 121 | binary.BigEndian.PutUint32(value[1:5], tlv.ExtLocalCircuitId) 122 | if tlv.Adj3wayState != ADJ_3WAY_STATE_DOWN { 123 | if len(tlv.neighbourSystemId) != SYSTEM_ID_LENGTH { 124 | xx := fmt.Sprint("P2p3wayAdjacencyTlv.Serialize: NeighbourSystemId length invalid", len(tlv.neighbourSystemId), SYSTEM_ID_LENGTH) 125 | return nil, errors.New(xx) 126 | } 127 | copy(value[5:5+SYSTEM_ID_LENGTH], tlv.neighbourSystemId[0:SYSTEM_ID_LENGTH]) 128 | binary.BigEndian.PutUint32(value[5+SYSTEM_ID_LENGTH:9+SYSTEM_ID_LENGTH], tlv.NeighExtLocalCircuitId) 129 | } 130 | tlv.base.length = uint8(length) 131 | tlv.base.value = value 132 | data, err := tlv.base.Serialize() 133 | if err != nil { 134 | return data, err 135 | } 136 | return data, nil 137 | } 138 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_rfc5303_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "testing" 23 | ) 24 | 25 | func TestP2p3wayAdjacencyTlv(t *testing.T) { 26 | var err error 27 | 28 | p1 := []byte{0xf0, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00} 29 | 30 | t1, err := NewP2p3wayAdjacencyTlv() 31 | if err != nil { 32 | t.Fatalf("failed NewP2p3wayAdjacencyTlv: %#v", err) 33 | } 34 | 35 | err = t1.DecodeFromBytes(p1) 36 | if err != nil { 37 | t.Fatalf("failed DecodeFromBytes: %#v", err) 38 | } 39 | 40 | p2, err := t1.Serialize() 41 | if err != nil { 42 | t.Fatalf("failed Serialize: %#v\n%x", err, p2) 43 | } 44 | 45 | if !bytes.Equal(p1, p2) { 46 | t.Fatalf("failed !Equal") 47 | } 48 | 49 | p3 := []byte{0xf0, 0x0f, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0x00, 0x00, 0x00, 52 | } 53 | 54 | t2, err := NewP2p3wayAdjacencyTlv() 55 | if err != nil { 56 | t.Fatalf("failed NewP2p3wayAdjacencyTlv: %#v", err) 57 | } 58 | 59 | err = t2.DecodeFromBytes(p3) 60 | if err != nil { 61 | t.Fatalf("failed DecodeFromBytes: %#v", err) 62 | } 63 | 64 | p4, err := t2.Serialize() 65 | if err != nil { 66 | t.Fatalf("failed Serialize: %#v\n%x", err, p4) 67 | } 68 | 69 | if !bytes.Equal(p3, p4) { 70 | t.Fatalf("failed !Equal") 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_rfc5305_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "testing" 23 | ) 24 | 25 | func TestExtendedIsReachabilityTlv(t *testing.T) { 26 | var err error 27 | p1 := []byte{0x16, 0x16, 28 | 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x00, 0x00, 0x00, 0x0a, 0x00, 29 | 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x00, 0x00, 0x0a, 0x00, 30 | } 31 | 32 | t1, err := NewExtendedIsReachabilityTlv() 33 | if err != nil { 34 | t.Fatalf("failed NewExtendedIsReachabilityTlv: %#v", err) 35 | } 36 | 37 | err = t1.DecodeFromBytes(p1) 38 | if err != nil { 39 | t.Fatalf("failed DecodeFromBytes: %#v", err) 40 | } 41 | 42 | p2, err := t1.Serialize() 43 | if err != nil { 44 | t.Fatalf("failed Serialize: %#v", err) 45 | } 46 | 47 | if !bytes.Equal(p1, p2) { 48 | t.Fatalf("failed !Equal") 49 | } 50 | } 51 | 52 | func TestTrafficEngineeringRouterIdTlv(t *testing.T) { 53 | var err error 54 | p1 := []byte{0x86, 0x04, 0xc0, 0xa8, 0x01, 0x01} 55 | 56 | t1, err := NewTrafficEngineeringRouterIdTlv() 57 | if err != nil { 58 | t.Fatalf("failed NewTrafficEngineeringRouterIdTlv: %#v", err) 59 | } 60 | 61 | err = t1.DecodeFromBytes(p1) 62 | if err != nil { 63 | t.Fatalf("failed DecodeFromBytes: %#v", err) 64 | } 65 | 66 | p2, err := t1.Serialize() 67 | if err != nil { 68 | t.Fatalf("failed Serialize: %#v", err) 69 | } 70 | 71 | if !bytes.Equal(p1, p2) { 72 | t.Fatalf("failed !Equal") 73 | } 74 | } 75 | 76 | func TestExtendedIpReachabilityTlv(t *testing.T) { 77 | var err error 78 | p1 := []byte{0x87, 0x10, 79 | 0x00, 0x00, 0x00, 0x0a, 0x18, 0xc0, 0xa8, 0x01, 80 | 0x00, 0x00, 0x00, 0x0a, 0x18, 0xc0, 0xa8, 0x02, 81 | } 82 | 83 | t1, err := NewExtendedIpReachabilityTlv() 84 | if err != nil { 85 | t.Fatalf("failed NewExtendedIpReachabilityTlv: %#v", err) 86 | } 87 | 88 | err = t1.DecodeFromBytes(p1) 89 | if err != nil { 90 | t.Fatalf("failed DecodeFromBytes: %#v", err) 91 | } 92 | 93 | p2, err := t1.Serialize() 94 | if err != nil { 95 | t.Fatalf("failed Serialize: %#v", err) 96 | } 97 | 98 | if !bytes.Equal(p1, p2) { 99 | t.Fatalf("failed !Equal") 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /pkg/isis/packet/tlv_rfc5308_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import ( 21 | "bytes" 22 | "testing" 23 | ) 24 | 25 | func TestIpv6ReachabilityTlv(t *testing.T) { 26 | var err error 27 | p1 := []byte{0xec, 0x1c, 28 | 0x00, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x01, 29 | 0x00, 0x00, 0x00, 0x0a, 0x00, 0x40, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x02, 30 | } 31 | 32 | t1, err := NewIpv6ReachabilityTlv() 33 | if err != nil { 34 | t.Fatalf("failed NewIpv6ReachabilityTlv: %#v", err) 35 | } 36 | 37 | err = t1.DecodeFromBytes(p1) 38 | if err != nil { 39 | t.Fatalf("failed DecodeFromBytes: %#v", err) 40 | } 41 | 42 | p2, err := t1.Serialize() 43 | if err != nil { 44 | t.Fatalf("failed Serialize: %#v", err) 45 | } 46 | 47 | if !bytes.Equal(p1, p2) { 48 | t.Fatalf("failed !Equal") 49 | } 50 | } 51 | 52 | func TestIpv6InterfaceAddressTlv(t *testing.T) { 53 | var err error 54 | p1 := []byte{0xe8, 0x20, 55 | 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 56 | 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 57 | } 58 | 59 | t1, err := NewIpv6InterfaceAddressTlv() 60 | if err != nil { 61 | t.Fatalf("failed NewIpv6InterfaceAddressTlv: %#v", err) 62 | } 63 | 64 | err = t1.DecodeFromBytes(p1) 65 | if err != nil { 66 | t.Fatalf("failed DecodeFromBytes: %#v", err) 67 | } 68 | 69 | p2, err := t1.Serialize() 70 | if err != nil { 71 | t.Fatalf("failed Serialize: %#v", err) 72 | } 73 | 74 | if !bytes.Equal(p1, p2) { 75 | t.Fatalf("failed !Equal") 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /pkg/isis/server/adjacency.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "fmt" 22 | 23 | log "github.com/sirupsen/logrus" 24 | 25 | "github.com/m-asama/golsr/pkg/isis/packet" 26 | ) 27 | 28 | type AdjUsage uint8 29 | 30 | const ( 31 | _ AdjUsage = iota 32 | ADJ_USAGE_NONE 33 | ADJ_USAGE_LEVEL1 34 | ADJ_USAGE_LEVEL2 35 | ADJ_USAGE_LEVEL1AND2 36 | ) 37 | 38 | func (adjUsage AdjUsage) String() string { 39 | switch adjUsage { 40 | case ADJ_USAGE_NONE: 41 | return "ADJ_USAGE_NONE" 42 | case ADJ_USAGE_LEVEL1: 43 | return "ADJ_USAGE_LEVEL1" 44 | case ADJ_USAGE_LEVEL2: 45 | return "ADJ_USAGE_LEVEL2" 46 | case ADJ_USAGE_LEVEL1AND2: 47 | return "ADJ_USAGE_LEVEL1AND2" 48 | } 49 | log.Infof("") 50 | panic("") 51 | return fmt.Sprintf("AdjUsage(%d)", adjUsage) 52 | } 53 | 54 | type AdjType uint8 55 | 56 | const ( 57 | _ AdjType = iota 58 | ADJ_TYPE_LEVEL1_LAN 59 | ADJ_TYPE_LEVEL2_LAN 60 | ADJ_TYPE_P2P 61 | ) 62 | 63 | func (adjType AdjType) String() string { 64 | switch adjType { 65 | case ADJ_TYPE_LEVEL1_LAN: 66 | return "ADJ_TYPE_LEVEL1_LAN" 67 | case ADJ_TYPE_LEVEL2_LAN: 68 | return "ADJ_TYPE_LEVEL2_LAN" 69 | case ADJ_TYPE_P2P: 70 | return "ADJ_TYPE_P2P" 71 | } 72 | log.Infof("") 73 | panic("") 74 | return fmt.Sprintf("AdjType(%d)", adjType) 75 | } 76 | 77 | type Adjacency struct { 78 | adjState packet.Adj3wayState 79 | adjUsage AdjUsage 80 | adjType AdjType 81 | ipv4Supported bool 82 | ipv6Supported bool 83 | areaAddresses [][]byte 84 | ipv4Addresses []uint32 85 | ipv6Addresses [][4]uint32 86 | lanAddress [packet.SYSTEM_ID_LENGTH]byte 87 | systemId [packet.SYSTEM_ID_LENGTH]byte 88 | priority uint8 // LAN 89 | lanId [packet.NEIGHBOUR_ID_LENGTH]byte // LAN 90 | circuitId uint8 // P2P 91 | extendedCircuitId uint32 // P2P 92 | holdingTime uint16 93 | circuit *Circuit 94 | } 95 | 96 | func NewAdjacency(circuit *Circuit) (*Adjacency, error) { 97 | log.Debugf("enter") 98 | defer log.Debugf("exit") 99 | adjacency := &Adjacency{} 100 | adjacency.areaAddresses = make([][]byte, 0) 101 | adjacency.ipv4Addresses = make([]uint32, 0) 102 | adjacency.ipv6Addresses = make([][4]uint32, 0) 103 | adjacency.circuit = circuit 104 | return adjacency, nil 105 | } 106 | 107 | func (adjacency *Adjacency) level(level IsisLevel) bool { 108 | switch level { 109 | case ISIS_LEVEL_1: 110 | return adjacency.level1() 111 | case ISIS_LEVEL_2: 112 | return adjacency.level2() 113 | } 114 | log.Infof("") 115 | panic("") 116 | return false 117 | } 118 | 119 | func (adjacency *Adjacency) level1() bool { 120 | return adjacency.adjUsage == ADJ_USAGE_LEVEL1 || 121 | adjacency.adjUsage == ADJ_USAGE_LEVEL1AND2 122 | } 123 | 124 | func (adjacency *Adjacency) level2() bool { 125 | return adjacency.adjUsage == ADJ_USAGE_LEVEL2 || 126 | adjacency.adjUsage == ADJ_USAGE_LEVEL1AND2 127 | } 128 | 129 | func (adjacency *Adjacency) level1Only() bool { 130 | return adjacency.adjUsage == ADJ_USAGE_LEVEL1 131 | } 132 | 133 | func (adjacency *Adjacency) level2Only() bool { 134 | return adjacency.adjUsage == ADJ_USAGE_LEVEL2 135 | } 136 | -------------------------------------------------------------------------------- /pkg/isis/server/consts.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "time" 22 | ) 23 | 24 | const ( 25 | MAX_PATH_METRIC = 0xfe000000 26 | ZERO_AGE_LIFETIME = time.Minute * 1 27 | ) 28 | -------------------------------------------------------------------------------- /pkg/isis/server/flags.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "time" 22 | 23 | log "github.com/sirupsen/logrus" 24 | 25 | "github.com/m-asama/golsr/pkg/isis/packet" 26 | ) 27 | 28 | func (isis *IsisServer) srmFlag(ls *Ls, circuit *Circuit) bool { 29 | log.Debugf("enter: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 30 | defer log.Debugf("exit: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 31 | _, ok := ls.srmFlags[circuit.ifIndex()] 32 | if ok { 33 | return true 34 | } 35 | return false 36 | } 37 | 38 | func (isis *IsisServer) setSrmFlag(ls *Ls, circuit *Circuit) { 39 | log.Debugf("enter: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 40 | defer log.Debugf("exit: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 41 | if ls.pdu.SequenceNumber == 0 { 42 | log.Debugf("ls.pdu.SequenceNumber == 0") 43 | return 44 | } 45 | if !circuit.ready() { 46 | log.Debugf("!circuit.ready()") 47 | return 48 | } 49 | ls.srmFlags[circuit.ifIndex()] = nil 50 | } 51 | 52 | func (isis *IsisServer) setSrmFlagAll(ls *Ls) { 53 | log.Debugf("enter: lspid=%x", ls.pdu.LspId()) 54 | defer log.Debugf("exit: lspid=%x", ls.pdu.LspId()) 55 | if ls.pdu.SequenceNumber == 0 { 56 | return 57 | } 58 | for _, cirtmp := range isis.circuitDb { 59 | if !cirtmp.ready() { 60 | continue 61 | } 62 | ls.srmFlags[cirtmp.ifIndex()] = nil 63 | } 64 | } 65 | 66 | func (isis *IsisServer) setSrmFlagOtherThan(ls *Ls, circuit *Circuit) { 67 | log.Debugf("enter: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 68 | defer log.Debugf("exit: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 69 | if ls.pdu.SequenceNumber == 0 { 70 | return 71 | } 72 | for _, cirtmp := range isis.circuitDb { 73 | if !cirtmp.ready() { 74 | continue 75 | } 76 | if cirtmp.ifIndex() == circuit.ifIndex() { 77 | continue 78 | } 79 | ls.srmFlags[cirtmp.ifIndex()] = nil 80 | } 81 | } 82 | 83 | func (isis *IsisServer) setSrmFlagForCircuit(circuit *Circuit) { 84 | log.Debugf("enter: circuit=%s", circuit.name) 85 | defer log.Debugf("exit: circuit=%s", circuit.name) 86 | isis.lock.Lock() 87 | defer isis.lock.Unlock() 88 | for _, level := range ISIS_LEVEL_ALL { 89 | for _, lstmp := range isis.lsDb[level] { 90 | isis.setSrmFlag(lstmp, circuit) 91 | } 92 | } 93 | } 94 | 95 | func (isis *IsisServer) clearSrmFlag(ls *Ls, circuit *Circuit) { 96 | log.Debugf("enter: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 97 | defer log.Debugf("exit: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 98 | delete(ls.srmFlags, circuit.ifIndex()) 99 | } 100 | 101 | func (isis *IsisServer) ssnFlag(ls *Ls, circuit *Circuit) bool { 102 | log.Debugf("enter: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 103 | defer log.Debugf("exit: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 104 | _, ok := ls.ssnFlags[circuit.ifIndex()] 105 | if ok { 106 | return true 107 | } 108 | return false 109 | } 110 | 111 | func (isis *IsisServer) setSsnFlag(ls *Ls, circuit *Circuit) { 112 | log.Debugf("enter: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 113 | defer log.Debugf("exit: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 114 | if !circuit.ready() { 115 | log.Debugf("!circuit.ready()") 116 | return 117 | } 118 | ls.ssnFlags[circuit.ifIndex()] = nil 119 | } 120 | 121 | func (isis *IsisServer) clearSsnFlag(ls *Ls, circuit *Circuit) { 122 | log.Debugf("enter: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 123 | defer log.Debugf("exit: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 124 | delete(ls.ssnFlags, circuit.ifIndex()) 125 | } 126 | 127 | func (isis *IsisServer) clearSsnFlagOtherThan(ls *Ls, circuit *Circuit) { 128 | log.Debugf("enter: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 129 | defer log.Debugf("exit: lspid=%x circuit=%s", ls.pdu.LspId(), circuit.name) 130 | for _, cirtmp := range isis.circuitDb { 131 | if cirtmp.ifIndex() == circuit.ifIndex() { 132 | continue 133 | } 134 | delete(ls.ssnFlags, cirtmp.ifIndex()) 135 | } 136 | } 137 | 138 | func (isis *IsisServer) rescheduleHandleFlags(interval uint16) { 139 | log.Debugf("enter") 140 | defer log.Debugf("exit") 141 | time.Sleep(time.Second * time.Duration(interval)) 142 | isis.lock.Lock() 143 | defer isis.lock.Unlock() 144 | retrans := isis.handleSrmFlags() 145 | if len(retrans) > 0 { 146 | for interval, _ := range retrans { 147 | go isis.rescheduleHandleFlags(interval) 148 | } 149 | } 150 | } 151 | 152 | func (isis *IsisServer) scheduleHandleFlags() { 153 | log.Debugf("enter") 154 | defer log.Debugf("exit") 155 | time.Sleep(33 * time.Millisecond) 156 | isis.lock.Lock() 157 | defer isis.lock.Unlock() 158 | retrans := isis.handleSrmFlags() 159 | isis.handleSsnFlags() 160 | if len(retrans) > 0 { 161 | for interval, _ := range retrans { 162 | go isis.rescheduleHandleFlags(interval) 163 | } 164 | } 165 | } 166 | 167 | func (isis *IsisServer) handleSrmFlags() map[uint16]bool { 168 | log.Debugf("enter") 169 | defer log.Debugf("exit") 170 | retrans := make(map[uint16]bool) 171 | for _, level := range ISIS_LEVEL_ALL { 172 | for _, ls := range isis.lsDb[level] { 173 | for ifitmp, sentOld := range ls.srmFlags { 174 | circuit := isis.findCircuitByIfIndex(ifitmp) 175 | if circuit == nil { 176 | continue 177 | } 178 | interval := circuit.lspRetransmitInterval() 179 | thresh := time.Now() 180 | thresh = thresh.Add(-1 * time.Second * time.Duration(interval)) 181 | thresh = thresh.Add(33 * time.Millisecond) 182 | if sentOld != nil && 183 | sentOld.After(thresh) { 184 | continue 185 | } 186 | sentNew := time.Now() 187 | circuit.sendLs(ls.pdu) 188 | ls.srmFlags[ifitmp] = &sentNew 189 | retrans[interval] = true 190 | if circuit.configBcast() { 191 | isis.clearSrmFlag(ls, circuit) 192 | } 193 | } 194 | } 195 | } 196 | return retrans 197 | } 198 | 199 | func (isis *IsisServer) handleSsnFlags() { 200 | for _, level := range ISIS_LEVEL_ALL { 201 | lsstmp := make(map[int][]*Ls) 202 | for _, ls := range isis.lsDb[level] { 203 | for ifitmp, _ := range ls.ssnFlags { 204 | circuit := isis.findCircuitByIfIndex(ifitmp) 205 | if circuit == nil { 206 | continue 207 | } 208 | lss, ok := lsstmp[ifitmp] 209 | if !ok { 210 | lss = make([]*Ls, 0) 211 | } 212 | lss = append(lss, ls) 213 | lsstmp[ifitmp] = lss 214 | } 215 | } 216 | for ifitmp, lss := range lsstmp { 217 | circuit := isis.findCircuitByIfIndex(ifitmp) 218 | if circuit == nil { 219 | continue 220 | } 221 | lsps := make([]*packet.LsPdu, len(lss)) 222 | for i, _ := range lss { 223 | lsps[i] = lss[i].pdu 224 | } 225 | circuit.sendPsn(level.pduTypePsnp(), lsps) 226 | for _, ls := range lss { 227 | isis.clearSsnFlag(ls, circuit) 228 | } 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /pkg/isis/server/linkstate.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "bytes" 22 | "time" 23 | 24 | log "github.com/sirupsen/logrus" 25 | 26 | "github.com/m-asama/golsr/pkg/isis/packet" 27 | ) 28 | 29 | func (circuit *Circuit) sendLs(lsp *packet.LsPdu) { 30 | log.Debugf("enter: %s", circuit.name) 31 | defer log.Debugf("exit: %s", circuit.name) 32 | 33 | if lsp.SequenceNumber == 0 || !circuit.ready() { 34 | return 35 | } 36 | 37 | circuit.lsSenderCh <- lsp 38 | } 39 | 40 | func (circuit *Circuit) receiveLs(pdu *packet.LsPdu, lanAddress [packet.SYSTEM_ID_LENGTH]byte) { 41 | log.Debugf("enter: %s", circuit.name) 42 | defer log.Debugf("exit: %s", circuit.name) 43 | 44 | if !circuit.ready() { 45 | return 46 | } 47 | 48 | if !pdu.BaseValid() { 49 | return 50 | } 51 | 52 | // iso10589 p.34 7.3.15.1 a) 2) 53 | if circuit.level1Only() && pdu.PduType() == packet.PDU_TYPE_LEVEL2_LSP { 54 | return 55 | } 56 | 57 | // iso10589 p.34 7.3.15.1 a) 3) 58 | if circuit.level2Only() && pdu.PduType() == packet.PDU_TYPE_LEVEL1_LSP { 59 | return 60 | } 61 | 62 | var adjacency *Adjacency 63 | switch pdu.PduType() { 64 | case packet.PDU_TYPE_LEVEL1_LSP: 65 | adjacency = circuit.findAdjacency(lanAddress, packet.CIRCUIT_TYPE_LEVEL1_ONLY) 66 | case packet.PDU_TYPE_LEVEL2_LSP: 67 | adjacency = circuit.findAdjacency(lanAddress, packet.CIRCUIT_TYPE_LEVEL2_ONLY) 68 | } 69 | if adjacency == nil { 70 | adjacency = circuit.findAdjacency(lanAddress, packet.CIRCUIT_TYPE_BOTH_LEVEL1_AND_LEVEL2) 71 | } 72 | if adjacency == nil { 73 | return 74 | } 75 | 76 | // iso10589 p.34 7.3.15.1 a) 6) 77 | if circuit.configBcast() && 78 | !bytes.Equal(lanAddress[:], adjacency.lanAddress[:]) { 79 | return 80 | } 81 | if pdu.PduType() == packet.PDU_TYPE_LEVEL1_LSP && 82 | !adjacency.level1() { 83 | return 84 | } 85 | if pdu.PduType() == packet.PDU_TYPE_LEVEL2_LSP && 86 | !adjacency.level2() { 87 | return 88 | } 89 | 90 | // iso10589 p.35 7.3.15.1 a) 7), 8) 91 | 92 | var level IsisLevel 93 | switch pdu.PduType() { 94 | case packet.PDU_TYPE_LEVEL1_LSP: 95 | level = ISIS_LEVEL_1 96 | case packet.PDU_TYPE_LEVEL2_LSP: 97 | level = ISIS_LEVEL_2 98 | default: 99 | return 100 | } 101 | currentLs := circuit.isis.lookupLsp(level, pdu.LspId()) 102 | lspId := pdu.LspId() 103 | if pdu.RemainingLifetime == 0 { 104 | // iso10589 p.35 7.3.15.1 b) 105 | circuit.networkWidePurge(pdu, currentLs) 106 | } else if bytes.Equal(lspId[0:packet.SYSTEM_ID_LENGTH], circuit.isis.systemId[0:packet.SYSTEM_ID_LENGTH]) { 107 | if currentLs == nil || !currentLs.origin { 108 | // iso10589 p.35 7.3.15.1 c) 109 | circuit.networkWidePurge(pdu, currentLs) 110 | } else { 111 | // iso10589 p.35 7.3.15.1 d) 112 | currentLs.pdu.SequenceNumber++ 113 | currentLs.pdu.RemainingLifetime = circuit.isis.lspLifetime() 114 | currentLs.pdu.SetChecksum() 115 | circuit.isis.setSrmFlagAll(currentLs) 116 | } 117 | } else { 118 | // iso10589 p.35 7.3.15.1 e) 119 | if currentLs == nil || pdu.SequenceNumber > currentLs.pdu.SequenceNumber { 120 | // iso10589 p.35 7.3.15.1 e) 1) 121 | ls := circuit.isis.insertLsp(pdu, false, nil) 122 | circuit.isis.setSrmFlagOtherThan(ls, circuit) 123 | circuit.isis.clearSrmFlag(ls, circuit) 124 | if !circuit.configBcast() { 125 | circuit.isis.setSsnFlag(ls, circuit) 126 | } 127 | } else if pdu.SequenceNumber == currentLs.pdu.SequenceNumber { 128 | // iso10589 p.36 7.3.15.1 e) 2) 129 | circuit.isis.clearSrmFlag(currentLs, circuit) 130 | if !circuit.configBcast() { 131 | circuit.isis.setSsnFlag(currentLs, circuit) 132 | } 133 | } else if pdu.SequenceNumber < currentLs.pdu.SequenceNumber { 134 | // iso10589 p.35 7.3.15.1 e) 3) 135 | circuit.isis.setSrmFlag(currentLs, circuit) 136 | circuit.isis.clearSsnFlag(currentLs, circuit) 137 | } 138 | } 139 | 140 | go circuit.isis.scheduleHandleFlags() 141 | } 142 | 143 | func (circuit *Circuit) networkWidePurge(pdu *packet.LsPdu, currentLs *Ls) { 144 | log.Debugf("enter: %s", circuit.name) 145 | defer log.Debugf("exit: %s", circuit.name) 146 | // iso10589 p.40 7.3.16.4 147 | if currentLs == nil { 148 | // iso10589 p.41 7.3.16.4 a) 149 | // send an acknowledgement of the LSP on circuit C, but 150 | // shall not retain the LSP after the acknowledgement has been sent. 151 | lsps := make([]*packet.LsPdu, 1) 152 | lsps[0] = pdu 153 | var pduType packet.PduType 154 | switch pdu.PduType() { 155 | case packet.PDU_TYPE_LEVEL1_LSP: 156 | pduType = packet.PDU_TYPE_LEVEL1_PSNP 157 | case packet.PDU_TYPE_LEVEL2_LSP: 158 | pduType = packet.PDU_TYPE_LEVEL2_PSNP 159 | default: 160 | return 161 | } 162 | circuit.sendPsn(pduType, lsps) 163 | timeNow := time.Now() 164 | ls := circuit.isis.insertLsp(pdu, false, nil) 165 | ls.expired = &timeNow 166 | } else if !currentLs.origin { 167 | // iso10589 p.41 7.3.16.4 b) 168 | if pdu.SequenceNumber > currentLs.pdu.SequenceNumber || 169 | currentLs.pdu.RemainingLifetime != 0 { 170 | // iso10589 p.41 7.3.16.4 b) 1) 171 | timeNow := time.Now() 172 | ls := circuit.isis.insertLsp(pdu, false, nil) 173 | ls.expired = &timeNow 174 | circuit.isis.setSrmFlagOtherThan(ls, circuit) 175 | circuit.isis.clearSrmFlag(ls, circuit) 176 | if !circuit.configBcast() { 177 | circuit.isis.setSsnFlag(ls, circuit) 178 | } 179 | circuit.isis.clearSsnFlagOtherThan(ls, circuit) 180 | } else if pdu.SequenceNumber == currentLs.pdu.SequenceNumber && 181 | currentLs.pdu.RemainingLifetime == 0 { 182 | // iso10589 p.41 7.3.16.4 b) 2) 183 | circuit.isis.clearSrmFlag(currentLs, circuit) 184 | if !circuit.configBcast() { 185 | circuit.isis.setSsnFlag(currentLs, circuit) 186 | } 187 | } else if pdu.SequenceNumber < currentLs.pdu.SequenceNumber { 188 | // iso10589 p.41 7.3.16.4 b) 3) 189 | circuit.isis.setSrmFlag(currentLs, circuit) 190 | circuit.isis.clearSsnFlag(currentLs, circuit) 191 | } 192 | } else { 193 | // iso10589 p.41 7.3.16.4 c) 194 | currentLs.pdu.SequenceNumber++ 195 | currentLs.pdu.RemainingLifetime = circuit.isis.lspLifetime() 196 | currentLs.pdu.SetChecksum() 197 | circuit.isis.setSrmFlagAll(currentLs) 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /pkg/isis/server/lsdb.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "bytes" 22 | "errors" 23 | "sort" 24 | "time" 25 | 26 | log "github.com/sirupsen/logrus" 27 | 28 | "github.com/m-asama/golsr/internal/pkg/util" 29 | "github.com/m-asama/golsr/pkg/isis/packet" 30 | ) 31 | 32 | type Ls struct { 33 | pdu *packet.LsPdu 34 | origin bool 35 | srmFlags map[int]*time.Time 36 | ssnFlags map[int]*time.Time 37 | generated *time.Time 38 | expired *time.Time 39 | } 40 | 41 | type Lss []*Ls 42 | 43 | func (lss Lss) Len() int { 44 | return len(lss) 45 | } 46 | 47 | func (lss Lss) Swap(i, j int) { 48 | lss[i], lss[j] = lss[j], lss[i] 49 | } 50 | 51 | func (lss Lss) Less(i, j int) bool { 52 | li := lss[i].pdu.LspId() 53 | lj := lss[j].pdu.LspId() 54 | return bytes.Compare(li[:], lj[:]) < 0 55 | } 56 | 57 | func NewLs(pdu *packet.LsPdu, origin bool, generated *time.Time) (*Ls, error) { 58 | log.Debugf("enter") 59 | defer log.Debugf("exit") 60 | ls := Ls{ 61 | pdu: pdu, 62 | origin: origin, 63 | generated: generated, 64 | } 65 | ls.srmFlags = make(map[int]*time.Time) 66 | ls.ssnFlags = make(map[int]*time.Time) 67 | return &ls, nil 68 | } 69 | 70 | func (isis *IsisServer) lspLevel(lsp *packet.LsPdu) (IsisLevel, error) { 71 | log.Debugf("enter") 72 | defer log.Debugf("exit") 73 | if lsp == nil { 74 | return 0, errors.New("lsp invalid") 75 | } 76 | switch lsp.PduType() { 77 | case packet.PDU_TYPE_LEVEL1_LSP: 78 | return ISIS_LEVEL_1, nil 79 | case packet.PDU_TYPE_LEVEL2_LSP: 80 | return ISIS_LEVEL_2, nil 81 | } 82 | return 0, errors.New("level invalid") 83 | } 84 | 85 | func (isis *IsisServer) insertLsp(lsp *packet.LsPdu, origin bool, generated *time.Time) *Ls { 86 | log.Debugf("enter: lspid=%x origin=%s generated=%s", lsp.LspId(), origin, generated) 87 | defer log.Debugf("exit: lspid=%x origin=%s generated=%s", lsp.LspId(), origin, generated) 88 | level, err := isis.lspLevel(lsp) 89 | if err != nil { 90 | return nil 91 | } 92 | isis.lock.Lock() 93 | defer isis.lock.Unlock() 94 | lsDb := make([]*Ls, 0) 95 | for _, lstmp := range isis.lsDb[level] { 96 | ll := lstmp.pdu.LspId() 97 | lr := lsp.LspId() 98 | if !bytes.Equal(ll[:], lr[:]) { 99 | lsDb = append(lsDb, lstmp) 100 | } 101 | } 102 | ls, _ := NewLs(lsp, origin, generated) 103 | lsDb = append(lsDb, ls) 104 | isis.lsDb[level] = lsDb 105 | isis.updateChSend(&UpdateChMsg{ 106 | msgType: UPDATE_CH_MSG_TYPE_LSDB_CHANGED, 107 | }) 108 | return ls 109 | } 110 | 111 | func (isis *IsisServer) deleteLsp(ls *Ls, hasLock bool) { 112 | log.Debugf("enter: lspid=%x", ls.pdu.LspId()) 113 | defer log.Debugf("exit: lspid=%x", ls.pdu.LspId()) 114 | level, err := isis.lspLevel(ls.pdu) 115 | if err != nil { 116 | return 117 | } 118 | if !hasLock { 119 | isis.lock.Lock() 120 | defer isis.lock.Unlock() 121 | } 122 | lsDb := make([]*Ls, 0) 123 | for _, lstmp := range isis.lsDb[level] { 124 | if lstmp != ls { 125 | lsDb = append(lsDb, lstmp) 126 | } 127 | } 128 | isis.lsDb[level] = lsDb 129 | isis.updateChSend(&UpdateChMsg{ 130 | msgType: UPDATE_CH_MSG_TYPE_LSDB_CHANGED, 131 | }) 132 | } 133 | 134 | func (isis *IsisServer) lookupLsp(level IsisLevel, lspId [packet.LSP_ID_LENGTH]byte) *Ls { 135 | log.Debugf("enter: level=%s lspid=%x", level, lspId) 136 | defer log.Debugf("exit: level=%s lspid=%x", level, lspId) 137 | isis.lock.RLock() 138 | defer isis.lock.RUnlock() 139 | for _, lstmp := range isis.lsDb[level] { 140 | ll := lstmp.pdu.LspId() 141 | if bytes.Equal(ll[:], lspId[:]) { 142 | return lstmp 143 | } 144 | } 145 | return nil 146 | } 147 | 148 | func (isis *IsisServer) originLss(level IsisLevel, nodeId uint8) []*Ls { 149 | log.Debugf("enter") 150 | defer log.Debugf("exit") 151 | isis.lock.RLock() 152 | defer isis.lock.RUnlock() 153 | lss := make([]*Ls, 0) 154 | for _, lstmp := range isis.lsDb[level] { 155 | ll := lstmp.pdu.LspId() 156 | if !lstmp.origin || 157 | !bytes.Equal(ll[0:packet.SYSTEM_ID_LENGTH], isis.systemId[0:packet.SYSTEM_ID_LENGTH]) || 158 | ll[packet.NEIGHBOUR_ID_LENGTH-1] != nodeId { 159 | continue 160 | } 161 | lss = append(lss, lstmp) 162 | } 163 | sort.Sort(Lss(lss)) 164 | return lss 165 | } 166 | 167 | func (isis *IsisServer) getReachabilities(level IsisLevel, neighId [packet.NEIGHBOUR_ID_LENGTH]byte) *Reachabilities { 168 | log.Debugf("enter: level=%s neighid=%x", level, neighId) 169 | defer log.Debugf("exit: level=%s neighid=%x", level, neighId) 170 | isis.lock.RLock() 171 | defer isis.lock.RUnlock() 172 | r := NewReachabilities() 173 | lss := make([]*Ls, 0) 174 | for _, lstmp := range isis.lsDb[level] { 175 | log.Debugf("%s: cand %x", level, lstmp.pdu.LspId()) 176 | ll := lstmp.pdu.LspId() 177 | if bytes.Equal(ll[0:packet.NEIGHBOUR_ID_LENGTH], neighId[0:packet.NEIGHBOUR_ID_LENGTH]) { 178 | log.Debugf("%s: found %x", level, lstmp.pdu.LspId()) 179 | lss = append(lss, lstmp) 180 | } 181 | } 182 | sort.Sort(Lss(lss)) 183 | for _, ls := range lss { 184 | log.Debugf("%s: do %x", level, ls.pdu.LspId()) 185 | widetlvs, _ := ls.pdu.ExtendedIsReachabilityTlvs() 186 | for _, tlv := range widetlvs { 187 | for _, n := range tlv.Neighbours() { 188 | isr := &IsReachability{} 189 | neighborId := n.NeighbourId() 190 | copy(isr.neighborId[0:packet.NEIGHBOUR_ID_LENGTH], 191 | neighborId[0:packet.NEIGHBOUR_ID_LENGTH]) 192 | isr.metric = n.DefaultMetric 193 | r.addIsReachability(isr) 194 | log.Debugf("%s: add wide %x", level, isr.neighborId) 195 | } 196 | } 197 | oldtlvs, _ := ls.pdu.IsNeighboursLspTlvs() 198 | for _, tlv := range oldtlvs { 199 | for _, n := range tlv.Neighbours() { 200 | isr := &IsReachability{} 201 | neighborId := n.NeighbourId() 202 | copy(isr.neighborId[0:packet.NEIGHBOUR_ID_LENGTH], 203 | neighborId[0:packet.NEIGHBOUR_ID_LENGTH]) 204 | isr.metric = uint32(n.DefaultMetric) 205 | r.addIsReachability(isr) 206 | log.Debugf("%s: add old %x", level, isr.neighborId) 207 | } 208 | } 209 | wideiptlvs, _ := ls.pdu.ExtendedIpReachabilityTlvs() 210 | for _, tlv := range wideiptlvs { 211 | for _, n := range tlv.Ipv4Prefixes() { 212 | log.Debugf("%s: XXX %x", level, n.Ipv4Prefix()) 213 | i4r := &Ipv4Reachability{} 214 | i4r.ipv4Prefix = n.Ipv4Prefix() 215 | i4r.prefixLength = n.PrefixLength() 216 | i4r.metric = n.MetricInformation 217 | r.addIpv4Reachability(i4r) 218 | log.Debugf("%s: add ipv4 wide %x/%d", level, i4r.ipv4Prefix, i4r.prefixLength) 219 | } 220 | } 221 | oldiptlvs, _ := ls.pdu.IpInternalReachInfoTlvs() 222 | for _, tlv := range oldiptlvs { 223 | for _, n := range tlv.IpSubnets() { 224 | log.Debugf("%s: XXX %x", level, n.IpAddress) 225 | i4r := &Ipv4Reachability{} 226 | i4r.ipv4Prefix = n.IpAddress 227 | i4r.prefixLength = util.Snmask42plen(n.SubnetMask) 228 | i4r.metric = uint32(n.DefaultMetric) 229 | r.addIpv4Reachability(i4r) 230 | log.Debugf("%s: add ipv4 old %x/%d", level, i4r.ipv4Prefix, i4r.prefixLength) 231 | } 232 | } 233 | ip6tlvs, _ := ls.pdu.Ipv6ReachabilityTlvs() 234 | for _, tlv := range ip6tlvs { 235 | for _, n := range tlv.Ipv6Prefixes() { 236 | i6r := &Ipv6Reachability{} 237 | i6r.ipv6Prefix = n.Ipv6Prefix() 238 | i6r.prefixLength = n.PrefixLength() 239 | i6r.metric = n.Metric 240 | r.addIpv6Reachability(i6r) 241 | log.Debugf("%s: add ipv6 %x:%x:%x:%x/%d", level, 242 | i6r.ipv6Prefix[0], i6r.ipv6Prefix[1], i6r.ipv6Prefix[2], i6r.ipv6Prefix[3], 243 | i6r.prefixLength) 244 | } 245 | } 246 | } 247 | return r 248 | } 249 | -------------------------------------------------------------------------------- /pkg/isis/server/periodic.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "time" 22 | 23 | log "github.com/sirupsen/logrus" 24 | ) 25 | 26 | func (isis *IsisServer) lsDbIter(ls *Ls) bool { 27 | log.Debugf("enter") 28 | defer log.Debugf("exit") 29 | changed := false 30 | if ls.pdu.RemainingLifetime > 0 { 31 | ls.pdu.RemainingLifetime-- 32 | } 33 | if ls.pdu.RemainingLifetime == 0 { 34 | if ls.expired == nil { 35 | expired := time.Now() 36 | ls.expired = &expired 37 | changed = true 38 | } 39 | if ls.expired.Before(time.Now().Add(-ZERO_AGE_LIFETIME)) { 40 | isis.deleteLsp(ls, true) 41 | } 42 | } 43 | return changed 44 | } 45 | 46 | func (isis *IsisServer) lsDbWalk() bool { 47 | log.Debugf("enter") 48 | defer log.Debugf("exit") 49 | isis.lock.Lock() 50 | defer isis.lock.Unlock() 51 | changed := false 52 | for _, level := range ISIS_LEVEL_ALL { 53 | for _, ls := range isis.lsDb[level] { 54 | if isis.lsDbIter(ls) { 55 | changed = true 56 | } 57 | } 58 | } 59 | return changed 60 | } 61 | 62 | func (isis *IsisServer) adjDbWalk() bool { 63 | log.Debugf("enter") 64 | defer log.Debugf("exit") 65 | isis.lock.Lock() 66 | defer isis.lock.Unlock() 67 | changed := false 68 | for _, circuit := range isis.circuitDb { 69 | for _, adjacency := range circuit.adjacencyDb { 70 | if adjacency.holdingTime > 0 { 71 | adjacency.holdingTime-- 72 | } 73 | if adjacency.holdingTime == 0 { 74 | circuit.removeAdjacency(adjacency.lanAddress, adjacency.adjType) 75 | circuit.isis.updateChSend(&UpdateChMsg{ 76 | msgType: UPDATE_CH_MSG_TYPE_ADJACENCY_DOWN, 77 | adjacency: adjacency, 78 | }) 79 | changed = true 80 | } 81 | } 82 | } 83 | return changed 84 | } 85 | 86 | func (isis *IsisServer) periodic(doneCh chan struct{}) { 87 | log.Debugf("enter") 88 | defer log.Debugf("exit") 89 | timer := time.NewTimer(0) 90 | started := time.Now() 91 | var counter time.Duration 92 | for { 93 | select { 94 | case <-doneCh: 95 | goto EXIT 96 | case <-timer.C: 97 | isis.lsDbWalk() 98 | isis.adjDbWalk() 99 | counter++ 100 | timer.Reset(started.Add(time.Second * counter).Sub(time.Now())) 101 | } 102 | } 103 | EXIT: 104 | } 105 | -------------------------------------------------------------------------------- /pkg/isis/server/seqnum.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "bytes" 22 | "time" 23 | 24 | log "github.com/sirupsen/logrus" 25 | 26 | "github.com/m-asama/golsr/pkg/isis/packet" 27 | ) 28 | 29 | func (circuit *Circuit) sendCsnInterval() time.Duration { 30 | interval := *circuit.ifConfig.Config.CsnpInterval 31 | return time.Duration(interval) 32 | } 33 | 34 | func (circuit *Circuit) sendCsn(pduType packet.PduType) { 35 | log.Debugf("enter: %s", circuit.name) 36 | defer log.Debugf("exit: %s", circuit.name) 37 | 38 | lsps := make([]*packet.LsPdu, 0) 39 | 40 | var lsDb []*Ls 41 | switch pduType { 42 | case packet.PDU_TYPE_LEVEL1_CSNP: 43 | lsDb = circuit.isis.lsDb[ISIS_LEVEL_1] 44 | case packet.PDU_TYPE_LEVEL2_CSNP: 45 | lsDb = circuit.isis.lsDb[ISIS_LEVEL_2] 46 | } 47 | for _, ls := range lsDb { 48 | if ls.pdu.RemainingLifetime == 0 { 49 | continue 50 | } 51 | lsps = append(lsps, ls.pdu) 52 | } 53 | 54 | startLspId := [packet.LSP_ID_LENGTH]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 55 | endLspId := [packet.LSP_ID_LENGTH]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} 56 | 57 | lspEntriesTlv, _ := packet.NewLspEntriesTlv() 58 | for _, lsp := range lsps { 59 | lspEntry, _ := packet.NewLspEntriesLspEntry(lsp.LspId()) 60 | lspEntry.RemainingLifetime = lsp.RemainingLifetime 61 | lspEntry.LspSeqNum = lsp.SequenceNumber 62 | lspEntry.Checksum = lsp.Checksum 63 | lspEntriesTlv.AddLspEntry(lspEntry) 64 | } 65 | 66 | var sourceId [packet.NEIGHBOUR_ID_LENGTH]byte 67 | copy(sourceId[0:packet.SYSTEM_ID_LENGTH], circuit.isis.systemId[0:packet.SYSTEM_ID_LENGTH]) 68 | csn, _ := packet.NewSnPdu(pduType) 69 | csn.SetSourceId(sourceId) 70 | csn.SetStartLspId(startLspId) 71 | csn.SetEndLspId(endLspId) 72 | csn.AddLspEntriesTlv(lspEntriesTlv) 73 | 74 | circuit.sendPdu(csn) 75 | } 76 | 77 | func (circuit *Circuit) sendPsn(pduType packet.PduType, lsps []*packet.LsPdu) { 78 | log.Debugf("enter: %s", circuit.name) 79 | defer log.Debugf("exit: %s", circuit.name) 80 | 81 | lspEntriesTlv, _ := packet.NewLspEntriesTlv() 82 | for _, lsp := range lsps { 83 | lspEntry, _ := packet.NewLspEntriesLspEntry(lsp.LspId()) 84 | lspEntry.RemainingLifetime = lsp.RemainingLifetime 85 | lspEntry.LspSeqNum = lsp.SequenceNumber 86 | lspEntry.Checksum = lsp.Checksum 87 | lspEntriesTlv.AddLspEntry(lspEntry) 88 | } 89 | 90 | var sourceId [packet.NEIGHBOUR_ID_LENGTH]byte 91 | copy(sourceId[0:packet.SYSTEM_ID_LENGTH], circuit.isis.systemId[0:packet.SYSTEM_ID_LENGTH]) 92 | psn, _ := packet.NewSnPdu(pduType) 93 | psn.SetSourceId(sourceId) 94 | psn.AddLspEntriesTlv(lspEntriesTlv) 95 | 96 | circuit.snSenderCh <- psn 97 | } 98 | 99 | func (circuit *Circuit) receiveSn(pdu *packet.SnPdu, lanAddress [packet.SYSTEM_ID_LENGTH]byte) { 100 | log.Debugf("enter: %s", circuit.name) 101 | defer log.Debugf("exit: %s", circuit.name) 102 | 103 | if !circuit.ready() { 104 | return 105 | } 106 | 107 | if !pdu.BaseValid() { 108 | return 109 | } 110 | 111 | // iso10589 p.36 7.3.15.2 a) 2) 112 | if circuit.level1Only() && 113 | (pdu.PduType() == packet.PDU_TYPE_LEVEL2_PSNP || pdu.PduType() == packet.PDU_TYPE_LEVEL2_CSNP) { 114 | return 115 | } 116 | 117 | // iso10589 p.36 7.3.15.2 a) 3) 118 | if circuit.level2Only() && 119 | (pdu.PduType() == packet.PDU_TYPE_LEVEL1_PSNP || pdu.PduType() == packet.PDU_TYPE_LEVEL1_CSNP) { 120 | return 121 | } 122 | 123 | if circuit.configBcast() { 124 | if (pdu.PduType() == packet.PDU_TYPE_LEVEL1_PSNP || pdu.PduType() == packet.PDU_TYPE_LEVEL1_CSNP) && 125 | !circuit.designated(ISIS_LEVEL_1) { 126 | return 127 | } 128 | if (pdu.PduType() == packet.PDU_TYPE_LEVEL2_PSNP || pdu.PduType() == packet.PDU_TYPE_LEVEL2_CSNP) && 129 | !circuit.designated(ISIS_LEVEL_2) { 130 | return 131 | } 132 | } 133 | 134 | var adjacency *Adjacency 135 | switch pdu.PduType() { 136 | case packet.PDU_TYPE_LEVEL1_PSNP, packet.PDU_TYPE_LEVEL1_CSNP: 137 | adjacency = circuit.findAdjacency(lanAddress, packet.CIRCUIT_TYPE_LEVEL1_ONLY) 138 | case packet.PDU_TYPE_LEVEL2_PSNP, packet.PDU_TYPE_LEVEL2_CSNP: 139 | adjacency = circuit.findAdjacency(lanAddress, packet.CIRCUIT_TYPE_LEVEL2_ONLY) 140 | } 141 | if adjacency == nil { 142 | adjacency = circuit.findAdjacency(lanAddress, packet.CIRCUIT_TYPE_BOTH_LEVEL1_AND_LEVEL2) 143 | } 144 | if adjacency == nil { 145 | return 146 | } 147 | 148 | if circuit.configBcast() && 149 | !bytes.Equal(lanAddress[:], adjacency.lanAddress[:]) { 150 | return 151 | } 152 | if (pdu.PduType() == packet.PDU_TYPE_LEVEL1_PSNP || pdu.PduType() == packet.PDU_TYPE_LEVEL1_CSNP) && 153 | !adjacency.level1() { 154 | return 155 | } 156 | if (pdu.PduType() == packet.PDU_TYPE_LEVEL2_PSNP || pdu.PduType() == packet.PDU_TYPE_LEVEL2_CSNP) && 157 | !adjacency.level2() { 158 | return 159 | } 160 | 161 | // iso10589 p.37 7.3.15.2 a) 7), 8) 162 | 163 | // iso10589 p.37 7.3.15.2 b) 164 | lspEntriesTlvs, _ := pdu.LspEntriesTlvs() 165 | for _, lspEntriesTlv := range lspEntriesTlvs { 166 | for _, lspEntry := range lspEntriesTlv.LspEntries() { 167 | circuit.handleLspEntry(pdu.PduType(), lspEntry.LspId(), lspEntry.LspSeqNum, 168 | lspEntry.RemainingLifetime, lspEntry.Checksum) 169 | } 170 | } 171 | 172 | // iso10589 p.37 7.3.15.2 c) 173 | if pdu.PduType() == packet.PDU_TYPE_LEVEL1_CSNP || pdu.PduType() == packet.PDU_TYPE_LEVEL2_CSNP { 174 | // XXX 175 | } 176 | 177 | go circuit.isis.scheduleHandleFlags() 178 | } 179 | 180 | func (circuit *Circuit) handleLspEntry(pduType packet.PduType, lspId [packet.LSP_ID_LENGTH]byte, lspSeqNum uint32, 181 | remainingLifetime, checksum uint16) { 182 | log.Debugf("enter: %s", circuit.name) 183 | defer log.Debugf("exit: %s", circuit.name) 184 | // iso10589 p.37 7.3.15.2 b) 1) 185 | var level IsisLevel 186 | switch pduType { 187 | case packet.PDU_TYPE_LEVEL1_PSNP: 188 | level = ISIS_LEVEL_1 189 | case packet.PDU_TYPE_LEVEL2_PSNP: 190 | level = ISIS_LEVEL_2 191 | default: 192 | log.Infof("pdu type invalid") 193 | return 194 | } 195 | currentLs := circuit.isis.lookupLsp(level, lspId) 196 | if currentLs == nil { 197 | // iso10589 p.37 7.3.15.2 b) 5) 198 | if remainingLifetime != 0 && 199 | checksum != 0 && 200 | lspSeqNum != 0 { 201 | var lsPduType packet.PduType 202 | switch pduType { 203 | case packet.PDU_TYPE_LEVEL1_PSNP: 204 | lsPduType = packet.PDU_TYPE_LEVEL1_LSP 205 | case packet.PDU_TYPE_LEVEL2_PSNP: 206 | lsPduType = packet.PDU_TYPE_LEVEL2_LSP 207 | } 208 | lsp, _ := packet.NewLsPdu(lsPduType) 209 | lsp.SetLspId(lspId) 210 | ls := circuit.isis.insertLsp(lsp, false, nil) 211 | circuit.isis.setSsnFlag(ls, circuit) 212 | } 213 | } else if lspSeqNum == currentLs.pdu.SequenceNumber { 214 | // iso10589 p.37 7.3.15.2 b) 2) 215 | if !circuit.configBcast() { 216 | circuit.isis.clearSrmFlag(currentLs, circuit) 217 | } 218 | } else if lspSeqNum < currentLs.pdu.SequenceNumber { 219 | // iso10589 p.37 7.3.15.2 b) 3) 220 | circuit.isis.clearSsnFlag(currentLs, circuit) 221 | circuit.isis.setSrmFlag(currentLs, circuit) 222 | } else if lspSeqNum > currentLs.pdu.SequenceNumber { 223 | // iso10589 p.37 7.3.15.2 b) 4) 224 | circuit.isis.setSsnFlag(currentLs, circuit) 225 | if !circuit.configBcast() { 226 | circuit.isis.clearSrmFlag(currentLs, circuit) 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /pkg/isis/server/socket.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "encoding/binary" 22 | "errors" 23 | "syscall" 24 | "unsafe" 25 | 26 | log "github.com/sirupsen/logrus" 27 | 28 | "github.com/m-asama/golsr/internal/pkg/kernel" 29 | "github.com/m-asama/golsr/pkg/isis/packet" 30 | ) 31 | 32 | func htons(s uint16) uint16 { 33 | b := []byte{byte(s & 0xff), byte(s >> 8)} 34 | return binary.BigEndian.Uint16(b) 35 | } 36 | 37 | func isisSocket(iface *kernel.Interface) (int, error) { 38 | var err error 39 | 40 | if iface == nil { 41 | s := "iface == nil" 42 | log.Infof(s) 43 | return -1, errors.New(s) 44 | } 45 | 46 | fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, int(htons(uint16(syscall.ETH_P_ALL)))) 47 | if err != nil { 48 | s := "syscall.Socket failed" 49 | log.Infof(s) 50 | return -1, errors.New(s) 51 | } 52 | 53 | filter := make([]SockFilter, 6) 54 | filter[0] = SockFilter{0x28, 0, 0, 0x0000000e - 14} 55 | filter[1] = SockFilter{0x15, 0, 3, 0x0000fefe} 56 | filter[2] = SockFilter{0x30, 0, 0, 0x00000011 - 14} 57 | filter[3] = SockFilter{0x15, 0, 1, 0x00000083} 58 | filter[4] = SockFilter{0x6, 0, 0, 0x00040000} 59 | filter[5] = SockFilter{0x6, 0, 0, 0x00000000} 60 | bpf := SockFprog{ 61 | Len: 6, 62 | Filter: (*SockFilter)(unsafe.Pointer(&filter[0])), 63 | } 64 | SetsockoptAttachFilter(fd, syscall.SOL_SOCKET, syscall.SO_ATTACH_FILTER, &bpf) 65 | if err != nil { 66 | s := "SetsockoptAttachFilter failed" 67 | log.Infof(s) 68 | return -1, errors.New(s) 69 | } 70 | 71 | addr := syscall.SockaddrLinklayer{ 72 | Protocol: syscall.ETH_P_ALL, 73 | Ifindex: iface.IfIndex, 74 | } 75 | addr.Protocol = htons(uint16(syscall.ETH_P_ALL)) 76 | err = syscall.Bind(fd, &addr) 77 | if err != nil { 78 | s := "syscall.Bind failed" 79 | log.Infof(s) 80 | return -1, errors.New(s) 81 | } 82 | 83 | mreqAddrs := [][]byte{packet.AllL1Iss, packet.AllL2Iss, packet.AllIss} 84 | for _, mreqAddr := range mreqAddrs { 85 | mreq := PacketMreq{ 86 | Ifindex: int32(iface.IfIndex), 87 | Type: syscall.PACKET_MR_MULTICAST, 88 | ALen: uint16(len(mreqAddr)), 89 | } 90 | copy(mreq.Address[0:6], mreqAddr[0:6]) 91 | mreq.Address[6] = 0x0 92 | mreq.Address[7] = 0x0 93 | 94 | err = SetsockoptPacketMreq(fd, syscall.SOL_PACKET, syscall.PACKET_ADD_MEMBERSHIP, &mreq) 95 | if err != nil { 96 | s := "SetsockoptPacketMreq failed" 97 | log.Infof(s) 98 | return -1, errors.New(s) 99 | } 100 | } 101 | 102 | return fd, nil 103 | } 104 | -------------------------------------------------------------------------------- /pkg/isis/server/syscall.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "syscall" 22 | "unsafe" 23 | ) 24 | 25 | var ( 26 | errEAGAIN error = syscall.EAGAIN 27 | errEINVAL error = syscall.EINVAL 28 | errENOENT error = syscall.ENOENT 29 | ) 30 | 31 | /* 32 | struct packet_mreq { 33 | int mr_ifindex; 34 | unsigned short mr_type; 35 | unsigned short mr_alen; 36 | unsigned char mr_address[8]; 37 | }; 38 | */ 39 | 40 | type PacketMreq struct { 41 | Ifindex int32 42 | Type uint16 43 | ALen uint16 44 | Address [8]byte 45 | } 46 | 47 | type SockFilter struct { 48 | Code uint16 49 | Jt uint8 50 | Jf uint8 51 | K uint32 52 | } 53 | 54 | type SockFprog struct { 55 | Len uint16 56 | Filter *SockFilter 57 | } 58 | 59 | func errnoErr(e syscall.Errno) error { 60 | switch e { 61 | case 0: 62 | return nil 63 | case syscall.EAGAIN: 64 | return errEAGAIN 65 | case syscall.EINVAL: 66 | return errEINVAL 67 | case syscall.ENOENT: 68 | return errENOENT 69 | } 70 | return e 71 | } 72 | 73 | func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) { 74 | _, _, e1 := syscall.Syscall6(syscall.SYS_SETSOCKOPT, 75 | uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0) 76 | if e1 != 0 { 77 | err = errnoErr(e1) 78 | } 79 | return 80 | } 81 | 82 | func SetsockoptPacketMreq(fd, level, opt int, mreq *PacketMreq) (err error) { 83 | return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq)) 84 | } 85 | 86 | func SetsockoptAttachFilter(fd, level, opt int, bpf *SockFprog) (err error) { 87 | return setsockopt(fd, level, opt, unsafe.Pointer(bpf), unsafe.Sizeof(*bpf)) 88 | } 89 | -------------------------------------------------------------------------------- /pkg/ospf/packet/packet.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package packet 19 | 20 | import () 21 | -------------------------------------------------------------------------------- /pkg/ospf/server/api.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "net" 22 | "strings" 23 | "sync" 24 | 25 | log "github.com/sirupsen/logrus" 26 | "golang.org/x/net/context" 27 | "google.golang.org/grpc" 28 | 29 | api "github.com/m-asama/golsr/api/ospf" 30 | _ "github.com/m-asama/golsr/internal/pkg/util" 31 | _ "github.com/m-asama/golsr/pkg/ospf/packet" 32 | ) 33 | 34 | type ApiServer struct { 35 | ospfServer *OspfServer 36 | grpcServer *grpc.Server 37 | hosts string 38 | } 39 | 40 | func NewApiServer(i *OspfServer, g *grpc.Server, hosts string) *ApiServer { 41 | log.Debugf("enter") 42 | defer log.Debugf("exit") 43 | grpc.EnableTracing = false 44 | s := &ApiServer{ 45 | ospfServer: i, 46 | grpcServer: g, 47 | hosts: hosts, 48 | } 49 | api.RegisterGoospfApiServer(g, s) 50 | return s 51 | } 52 | 53 | func (s *ApiServer) Serve(wg *sync.WaitGroup) { 54 | log.Debugf("enter") 55 | defer log.Debugf("exit") 56 | defer wg.Done() 57 | 58 | serve := func(host string) { 59 | log.Debugf("enter") 60 | defer log.Debugf("exit") 61 | defer wg.Done() 62 | lis, err := net.Listen("tcp", host) 63 | if err != nil { 64 | log.WithFields(log.Fields{ 65 | "Topic": "grpc", 66 | "Key": host, 67 | "Error": err, 68 | }).Warn("listen failed") 69 | return 70 | } 71 | err = s.grpcServer.Serve(lis) 72 | log.WithFields(log.Fields{ 73 | "Topic": "grpc", 74 | "Key": host, 75 | "Error": err, 76 | }).Warn("accept failed") 77 | } 78 | 79 | l := strings.Split(s.hosts, ",") 80 | for _, host := range l { 81 | wg.Add(1) 82 | go serve(host) 83 | } 84 | } 85 | 86 | func (s *ApiServer) Exit() { 87 | log.Debugf("enter") 88 | defer log.Debugf("exit") 89 | s.grpcServer.Stop() 90 | } 91 | 92 | func (s *ApiServer) Enable(ctx context.Context, in *api.EnableRequest) (*api.EnableResponse, error) { 93 | log.Debugf("enter") 94 | defer log.Debugf("exit") 95 | response := &api.EnableResponse{} 96 | if s.ospfServer.enable() { 97 | response.Result = "already enabled" 98 | } else { 99 | s.ospfServer.SetEnable() 100 | response.Result = "enabled" 101 | } 102 | return response, nil 103 | } 104 | 105 | func (s *ApiServer) Disable(ctx context.Context, in *api.DisableRequest) (*api.DisableResponse, error) { 106 | log.Debugf("enter") 107 | defer log.Debugf("exit") 108 | response := &api.DisableResponse{} 109 | if s.ospfServer.enable() { 110 | s.ospfServer.SetDisable() 111 | response.Result = "disabled" 112 | } else { 113 | response.Result = "already disabled" 114 | } 115 | return response, nil 116 | } 117 | -------------------------------------------------------------------------------- /pkg/ospf/server/decision.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "bytes" 22 | "fmt" 23 | "sync" 24 | 25 | log "github.com/sirupsen/logrus" 26 | ) 27 | 28 | type DecisionChMsgType uint8 29 | 30 | const ( 31 | _ DecisionChMsgType = iota 32 | DECISION_CH_MSG_TYPE_DO 33 | DECISION_CH_MSG_TYPE_EXIT 34 | ) 35 | 36 | func (msgType DecisionChMsgType) String() string { 37 | switch msgType { 38 | case DECISION_CH_MSG_TYPE_DO: 39 | return "DECISION_CH_MSG_TYPE_DO" 40 | case DECISION_CH_MSG_TYPE_EXIT: 41 | return "DECISION_CH_MSG_TYPE_EXIT" 42 | } 43 | log.Infof("") 44 | panic("") 45 | return fmt.Sprintf("DecisionChMsgType(%d)", msgType) 46 | } 47 | 48 | type DecisionChMsg struct { 49 | msgType DecisionChMsgType 50 | } 51 | 52 | func (msg *DecisionChMsg) String() string { 53 | var b bytes.Buffer 54 | fmt.Fprintf(&b, "%s", msg.msgType.String()) 55 | return b.String() 56 | } 57 | 58 | var decisionChSendCount int 59 | var decisionChSendCountLock sync.RWMutex 60 | 61 | func (ospf *OspfServer) decisionChSend(msg *DecisionChMsg) { 62 | go func() { 63 | decisionChSendCountLock.Lock() 64 | decisionChSendCount++ 65 | decisionChSendCountLock.Unlock() 66 | log.Debugf("decisionChSend[%d]: begin", decisionChSendCount) 67 | ospf.decisionCh <- msg 68 | log.Debugf("decisionChSend[%d]: end", decisionChSendCount) 69 | }() 70 | } 71 | 72 | func (ospf *OspfServer) decisionProcess() { 73 | log.Debugf("enter") 74 | defer log.Debugf("exit") 75 | for { 76 | msg := <-ospf.decisionCh 77 | switch msg.msgType { 78 | case DECISION_CH_MSG_TYPE_DO: 79 | case DECISION_CH_MSG_TYPE_EXIT: 80 | goto EXIT 81 | } 82 | } 83 | EXIT: 84 | } 85 | -------------------------------------------------------------------------------- /pkg/ospf/server/ospf.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "os" 22 | "os/signal" 23 | "sync" 24 | "syscall" 25 | 26 | log "github.com/sirupsen/logrus" 27 | 28 | "github.com/m-asama/golsr/internal/pkg/kernel" 29 | "github.com/m-asama/golsr/internal/pkg/ospf/config" 30 | _ "github.com/m-asama/golsr/pkg/ospf/packet" 31 | ) 32 | 33 | type OspfChMsg uint8 34 | 35 | const ( 36 | _ OspfChMsg = iota 37 | OSPF_CH_MSG_EXIT 38 | ) 39 | 40 | type OspfServer struct { 41 | ospfCh chan OspfChMsg 42 | decisionCh chan *DecisionChMsg 43 | updateCh chan *UpdateChMsg 44 | 45 | configFile string 46 | configType string 47 | config *config.OspfConfig 48 | kernel *kernel.KernelStatus 49 | 50 | lock sync.RWMutex 51 | } 52 | 53 | func NewOspfServer(configFile, configType string) *OspfServer { 54 | log.Debugf("enter") 55 | defer log.Debugf("exit") 56 | ospf := &OspfServer{ 57 | ospfCh: make(chan OspfChMsg), 58 | decisionCh: make(chan *DecisionChMsg, 8), 59 | updateCh: make(chan *UpdateChMsg, 8), 60 | configFile: configFile, 61 | configType: configType, 62 | config: config.NewOspfConfig(), 63 | kernel: kernel.NewKernelStatus(), 64 | } 65 | return ospf 66 | } 67 | 68 | func (ospf *OspfServer) Serve(wg *sync.WaitGroup) { 69 | log.Debugf("enter") 70 | defer log.Debugf("exit") 71 | defer wg.Done() 72 | 73 | log.Debugf("") 74 | 75 | var updateWg sync.WaitGroup 76 | 77 | sigCh := make(chan os.Signal, 1) 78 | configCh := make(chan *config.OspfConfig) 79 | if ospf.configFile != "" { 80 | updateWg.Add(1) 81 | go config.Serve(ospf.configFile, ospf.configType, configCh) 82 | } else { 83 | signal.Notify(sigCh, syscall.SIGHUP) 84 | } 85 | 86 | kernelCh := make(chan *kernel.KernelStatus) 87 | updateWg.Add(1) 88 | go kernel.Serve(kernelCh) 89 | 90 | periodicCh := make(chan struct{}) 91 | go ospf.periodic(periodicCh) 92 | 93 | go ospf.decisionProcess() 94 | go ospf.updateProcess(&updateWg) 95 | 96 | configReady := false 97 | kernelReady := false 98 | for { 99 | select { 100 | case <-sigCh: 101 | log.WithFields(log.Fields{ 102 | "Topic": "Config", 103 | }).Info("Do nothing") 104 | case msg := <-ospf.ospfCh: 105 | switch msg { 106 | case OSPF_CH_MSG_EXIT: 107 | log.Debugf("OSPF_CH_MSG_EXIT") 108 | periodicCh <- struct{}{} 109 | goto EXIT 110 | } 111 | case c := <-configCh: 112 | ospf.handleConfigChanged(c) 113 | if !configReady { 114 | updateWg.Done() 115 | configReady = true 116 | } 117 | case k := <-kernelCh: 118 | ospf.handleKernelChanged(k) 119 | if !kernelReady { 120 | updateWg.Done() 121 | kernelReady = true 122 | } 123 | } 124 | } 125 | EXIT: 126 | } 127 | 128 | func (ospf *OspfServer) Exit() { 129 | log.Debugf("enter") 130 | defer log.Debugf("exit") 131 | ospf.ospfCh <- OSPF_CH_MSG_EXIT 132 | } 133 | 134 | func (ospf *OspfServer) SetEnable() { 135 | log.Debugf("enter") 136 | defer log.Debugf("exit") 137 | *ospf.config.Config.Enable = true 138 | ospf.updateChSend(&UpdateChMsg{ 139 | msgType: UPDATE_CH_MSG_TYPE_OSPF_ENABLE, 140 | }) 141 | } 142 | 143 | func (ospf *OspfServer) SetDisable() { 144 | log.Debugf("enter") 145 | defer log.Debugf("exit") 146 | *ospf.config.Config.Enable = false 147 | ospf.updateChSend(&UpdateChMsg{ 148 | msgType: UPDATE_CH_MSG_TYPE_OSPF_DISABLE, 149 | }) 150 | } 151 | 152 | func (ospf *OspfServer) enable() bool { 153 | return *ospf.config.Config.Enable 154 | } 155 | 156 | func (ospf *OspfServer) handleConfigChanged(newConfig *config.OspfConfig) { 157 | log.Debugf("enter") 158 | defer log.Debugf("exit") 159 | /* 160 | added := make(map[string]*config.Interface) 161 | removed := make(map[string]*config.Interface) 162 | for _, iface := range ospf.config.Interfaces { 163 | removed[*iface.Config.Name] = iface 164 | } 165 | for _, iface := range newConfig.Interfaces { 166 | if _, ok := removed[*iface.Config.Name]; ok { 167 | delete(removed, *iface.Config.Name) 168 | } else { 169 | added[*iface.Config.Name] = iface 170 | } 171 | } 172 | for name, _ := range removed { 173 | log.Debugf("remove: %s", name) 174 | ospf.removeCircuit(name) 175 | } 176 | for name, iface := range added { 177 | log.Debugf("add: %s", name) 178 | ospf.addCircuit(name, iface) 179 | } 180 | for _, tmp := range ospf.circuitDb { 181 | for _, iface := range newConfig.Interfaces { 182 | if *tmp.ifConfig.Config.Name == *iface.Config.Name { 183 | tmp.ifConfig = iface 184 | } 185 | } 186 | } 187 | ospf.config = newConfig 188 | ospf.updateChSend(&UpdateChMsg{ 189 | msgType: UPDATE_CH_MSG_TYPE_CONFIG_CHANGED, 190 | }) 191 | */ 192 | } 193 | 194 | func (ospf *OspfServer) handleKernelChanged(newKernel *kernel.KernelStatus) { 195 | log.Debugf("enter") 196 | defer log.Debugf("exit") 197 | /* 198 | removed := make(map[string]*config.Interface) 199 | for _, iface := range ospf.config.Interfaces { 200 | removed[*iface.Config.Name] = iface 201 | } 202 | for _, iface := range newKernel.Interfaces { 203 | if _, ok := removed[iface.Name]; ok { 204 | delete(removed, iface.Name) 205 | } 206 | } 207 | for name, _ := range removed { 208 | log.Debugf("remove: %s", name) 209 | ospf.removeCircuit(name) 210 | } 211 | for _, tmp := range ospf.circuitDb { 212 | for _, iface := range newKernel.Interfaces { 213 | if tmp.ifKernel.IfIndex == iface.IfIndex { 214 | tmp.ifKernel = iface 215 | if tmp.name != tmp.ifKernel.Name { 216 | log.Debugf("renamed %s to %s", 217 | tmp.name, tmp.ifKernel.Name) 218 | tmp.name = tmp.ifKernel.Name 219 | *tmp.ifConfig.Config.Name = tmp.ifKernel.Name 220 | } 221 | } 222 | } 223 | } 224 | ospf.kernel = newKernel 225 | ospf.updateChSend(&UpdateChMsg{ 226 | msgType: UPDATE_CH_MSG_TYPE_KERNEL_CHANGED, 227 | }) 228 | */ 229 | } 230 | -------------------------------------------------------------------------------- /pkg/ospf/server/periodic.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "time" 22 | 23 | log "github.com/sirupsen/logrus" 24 | ) 25 | 26 | func (ospf *OspfServer) periodic(doneCh chan struct{}) { 27 | log.Debugf("enter") 28 | defer log.Debugf("exit") 29 | timer := time.NewTimer(0) 30 | started := time.Now() 31 | var counter time.Duration 32 | for { 33 | select { 34 | case <-doneCh: 35 | goto EXIT 36 | case <-timer.C: 37 | counter++ 38 | timer.Reset(started.Add(time.Second * counter).Sub(time.Now())) 39 | } 40 | } 41 | EXIT: 42 | } 43 | -------------------------------------------------------------------------------- /pkg/ospf/server/update.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2019-2019 Masakazu Asama. 3 | // Copyright (C) 2019-2019 Ginzado Co., Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14 | // implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package server 19 | 20 | import ( 21 | "bytes" 22 | "fmt" 23 | "sync" 24 | 25 | log "github.com/sirupsen/logrus" 26 | ) 27 | 28 | type UpdateChMsgType uint8 29 | 30 | const ( 31 | _ UpdateChMsgType = iota 32 | UPDATE_CH_MSG_TYPE_CONFIG_CHANGED 33 | UPDATE_CH_MSG_TYPE_KERNEL_CHANGED 34 | UPDATE_CH_MSG_TYPE_OSPF_ENABLE 35 | UPDATE_CH_MSG_TYPE_OSPF_DISABLE 36 | UPDATE_CH_MSG_TYPE_CIRCUIT_ENABLE 37 | UPDATE_CH_MSG_TYPE_CIRCUIT_DISABLE 38 | UPDATE_CH_MSG_TYPE_ADJACENCY_UP 39 | UPDATE_CH_MSG_TYPE_ADJACENCY_DOWN 40 | UPDATE_CH_MSG_TYPE_LSDB_CHANGED 41 | UPDATE_CH_MSG_TYPE_EXIT 42 | ) 43 | 44 | func (msgType UpdateChMsgType) String() string { 45 | switch msgType { 46 | case UPDATE_CH_MSG_TYPE_CONFIG_CHANGED: 47 | return "UPDATE_CH_MSG_TYPE_CONFIG_CHANGED" 48 | case UPDATE_CH_MSG_TYPE_KERNEL_CHANGED: 49 | return "UPDATE_CH_MSG_TYPE_KERNEL_CHANGED" 50 | case UPDATE_CH_MSG_TYPE_OSPF_ENABLE: 51 | return "UPDATE_CH_MSG_TYPE_OSPF_ENABLE" 52 | case UPDATE_CH_MSG_TYPE_OSPF_DISABLE: 53 | return "UPDATE_CH_MSG_TYPE_OSPF_DISABLE" 54 | case UPDATE_CH_MSG_TYPE_CIRCUIT_ENABLE: 55 | return "UPDATE_CH_MSG_TYPE_CIRCUIT_ENABLE" 56 | case UPDATE_CH_MSG_TYPE_CIRCUIT_DISABLE: 57 | return "UPDATE_CH_MSG_TYPE_CIRCUIT_DISABLE" 58 | case UPDATE_CH_MSG_TYPE_ADJACENCY_UP: 59 | return "UPDATE_CH_MSG_TYPE_ADJACENCY_UP" 60 | case UPDATE_CH_MSG_TYPE_ADJACENCY_DOWN: 61 | return "UPDATE_CH_MSG_TYPE_ADJACENCY_DOWN" 62 | case UPDATE_CH_MSG_TYPE_LSDB_CHANGED: 63 | return "UPDATE_CH_MSG_TYPE_LSDB_CHANGED" 64 | case UPDATE_CH_MSG_TYPE_EXIT: 65 | return "UPDATE_CH_MSG_TYPE_EXIT" 66 | } 67 | log.Infof("") 68 | panic("") 69 | return fmt.Sprintf("UpdateChMsgType(%d)", msgType) 70 | } 71 | 72 | type UpdateChMsg struct { 73 | msgType UpdateChMsgType 74 | } 75 | 76 | func (msg *UpdateChMsg) String() string { 77 | var b bytes.Buffer 78 | fmt.Fprintf(&b, "%s", msg.msgType.String()) 79 | return b.String() 80 | } 81 | 82 | var updateChSendCount int 83 | var updateChSendCountLock sync.RWMutex 84 | 85 | func (ospf *OspfServer) updateChSend(msg *UpdateChMsg) { 86 | go func() { 87 | updateChSendCountLock.Lock() 88 | updateChSendCount++ 89 | updateChSendCountLock.Unlock() 90 | log.Debugf("updateChSend[%d]: begin", updateChSendCount) 91 | ospf.updateCh <- msg 92 | log.Debugf("updateChSend[%d]: end", updateChSendCount) 93 | }() 94 | } 95 | 96 | func (ospf *OspfServer) updateProcess(wg *sync.WaitGroup) { 97 | log.Debugf("enter") 98 | defer log.Debugf("exit") 99 | wg.Wait() 100 | for { 101 | msg := <-ospf.updateCh 102 | log.Infof("%s", msg) 103 | switch msg.msgType { 104 | case UPDATE_CH_MSG_TYPE_CONFIG_CHANGED: 105 | case UPDATE_CH_MSG_TYPE_KERNEL_CHANGED: 106 | case UPDATE_CH_MSG_TYPE_OSPF_ENABLE: 107 | case UPDATE_CH_MSG_TYPE_OSPF_DISABLE: 108 | case UPDATE_CH_MSG_TYPE_EXIT: 109 | goto EXIT 110 | } 111 | } 112 | EXIT: 113 | } 114 | --------------------------------------------------------------------------------