github.com/osrg/gobgp@v2.0.0+incompatible/cmd/gobgpd/main.go (about) 1 // 2 // Copyright (C) 2014-2017 Nippon Telegraph and Telephone Corporation. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 // implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package main 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 "net/http" 23 _ "net/http/pprof" 24 "os" 25 "os/signal" 26 "runtime" 27 "syscall" 28 29 "github.com/golang/protobuf/ptypes/any" 30 "github.com/jessevdk/go-flags" 31 "github.com/kr/pretty" 32 log "github.com/sirupsen/logrus" 33 "golang.org/x/net/context" 34 "google.golang.org/grpc" 35 "google.golang.org/grpc/credentials" 36 37 api "github.com/osrg/gobgp/api" 38 "github.com/osrg/gobgp/internal/pkg/apiutil" 39 "github.com/osrg/gobgp/internal/pkg/config" 40 "github.com/osrg/gobgp/internal/pkg/table" 41 "github.com/osrg/gobgp/pkg/packet/bgp" 42 "github.com/osrg/gobgp/pkg/server" 43 ) 44 45 var version = "master" 46 47 func marshalRouteTargets(l []string) ([]*any.Any, error) { 48 rtList := make([]*any.Any, 0, len(l)) 49 for _, rtString := range l { 50 rt, err := bgp.ParseRouteTarget(rtString) 51 if err != nil { 52 return nil, err 53 } 54 rtList = append(rtList, apiutil.MarshalRT(rt)) 55 } 56 return rtList, nil 57 } 58 59 func main() { 60 sigCh := make(chan os.Signal, 1) 61 signal.Notify(sigCh, syscall.SIGTERM) 62 63 var opts struct { 64 ConfigFile string `short:"f" long:"config-file" description:"specifying a config file"` 65 ConfigType string `short:"t" long:"config-type" description:"specifying config type (toml, yaml, json)" default:"toml"` 66 LogLevel string `short:"l" long:"log-level" description:"specifying log level"` 67 LogPlain bool `short:"p" long:"log-plain" description:"use plain format for logging (json by default)"` 68 UseSyslog string `short:"s" long:"syslog" description:"use syslogd"` 69 Facility string `long:"syslog-facility" description:"specify syslog facility"` 70 DisableStdlog bool `long:"disable-stdlog" description:"disable standard logging"` 71 CPUs int `long:"cpus" description:"specify the number of CPUs to be used"` 72 GrpcHosts string `long:"api-hosts" description:"specify the hosts that gobgpd listens on" default:":50051"` 73 GracefulRestart bool `short:"r" long:"graceful-restart" description:"flag restart-state in graceful-restart capability"` 74 Dry bool `short:"d" long:"dry-run" description:"check configuration"` 75 PProfHost string `long:"pprof-host" description:"specify the host that gobgpd listens on for pprof" default:"localhost:6060"` 76 PProfDisable bool `long:"pprof-disable" description:"disable pprof profiling"` 77 TLS bool `long:"tls" description:"enable TLS authentication for gRPC API"` 78 TLSCertFile string `long:"tls-cert-file" description:"The TLS cert file"` 79 TLSKeyFile string `long:"tls-key-file" description:"The TLS key file"` 80 Version bool `long:"version" description:"show version number"` 81 } 82 _, err := flags.Parse(&opts) 83 if err != nil { 84 os.Exit(1) 85 } 86 87 if opts.Version { 88 fmt.Println("gobgpd version", version) 89 os.Exit(0) 90 } 91 92 if opts.CPUs == 0 { 93 runtime.GOMAXPROCS(runtime.NumCPU()) 94 } else { 95 if runtime.NumCPU() < opts.CPUs { 96 log.Errorf("Only %d CPUs are available but %d is specified", runtime.NumCPU(), opts.CPUs) 97 os.Exit(1) 98 } 99 runtime.GOMAXPROCS(opts.CPUs) 100 } 101 102 if !opts.PProfDisable { 103 go func() { 104 log.Println(http.ListenAndServe(opts.PProfHost, nil)) 105 }() 106 } 107 108 switch opts.LogLevel { 109 case "debug": 110 log.SetLevel(log.DebugLevel) 111 case "info": 112 log.SetLevel(log.InfoLevel) 113 default: 114 log.SetLevel(log.InfoLevel) 115 } 116 117 if opts.DisableStdlog { 118 log.SetOutput(ioutil.Discard) 119 } else { 120 log.SetOutput(os.Stdout) 121 } 122 123 if opts.UseSyslog != "" { 124 if err := addSyslogHook(opts.UseSyslog, opts.Facility); err != nil { 125 log.Error("Unable to connect to syslog daemon, ", opts.UseSyslog) 126 } 127 } 128 129 if opts.LogPlain { 130 if opts.DisableStdlog { 131 log.SetFormatter(&log.TextFormatter{ 132 DisableColors: true, 133 }) 134 } 135 } else { 136 log.SetFormatter(&log.JSONFormatter{}) 137 } 138 139 configCh := make(chan *config.BgpConfigSet) 140 if opts.Dry { 141 go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh) 142 c := <-configCh 143 if opts.LogLevel == "debug" { 144 pretty.Println(c) 145 } 146 os.Exit(0) 147 } 148 149 maxSize := 256 << 20 150 grpcOpts := []grpc.ServerOption{grpc.MaxRecvMsgSize(maxSize), grpc.MaxSendMsgSize(maxSize)} 151 if opts.TLS { 152 creds, err := credentials.NewServerTLSFromFile(opts.TLSCertFile, opts.TLSKeyFile) 153 if err != nil { 154 log.Fatalf("Failed to generate credentials: %v", err) 155 } 156 grpcOpts = append(grpcOpts, grpc.Creds(creds)) 157 } 158 159 log.Info("gobgpd started") 160 bgpServer := server.NewBgpServer(server.GrpcListenAddress(opts.GrpcHosts), server.GrpcOption(grpcOpts)) 161 go bgpServer.Serve() 162 163 if opts.ConfigFile != "" { 164 go config.ReadConfigfileServe(opts.ConfigFile, opts.ConfigType, configCh) 165 } 166 167 loop := func() { 168 var c *config.BgpConfigSet 169 for { 170 select { 171 case <-sigCh: 172 bgpServer.StopBgp(context.Background(), &api.StopBgpRequest{}) 173 return 174 case newConfig := <-configCh: 175 var added, deleted, updated []config.Neighbor 176 var addedPg, deletedPg, updatedPg []config.PeerGroup 177 var updatePolicy bool 178 179 if c == nil { 180 c = newConfig 181 if err := bgpServer.StartBgp(context.Background(), &api.StartBgpRequest{ 182 Global: config.NewGlobalFromConfigStruct(&c.Global), 183 }); err != nil { 184 log.Fatalf("failed to set global config: %s", err) 185 } 186 187 if newConfig.Zebra.Config.Enabled { 188 tps := c.Zebra.Config.RedistributeRouteTypeList 189 l := make([]string, 0, len(tps)) 190 for _, t := range tps { 191 l = append(l, string(t)) 192 } 193 if err := bgpServer.EnableZebra(context.Background(), &api.EnableZebraRequest{ 194 Url: c.Zebra.Config.Url, 195 RouteTypes: l, 196 Version: uint32(c.Zebra.Config.Version), 197 NexthopTriggerEnable: c.Zebra.Config.NexthopTriggerEnable, 198 NexthopTriggerDelay: uint32(c.Zebra.Config.NexthopTriggerDelay), 199 }); err != nil { 200 log.Fatalf("failed to set zebra config: %s", err) 201 } 202 } 203 204 if len(newConfig.Collector.Config.Url) > 0 { 205 log.Fatal("collector feature is not supported") 206 } 207 208 for _, c := range newConfig.RpkiServers { 209 if err := bgpServer.AddRpki(context.Background(), &api.AddRpkiRequest{ 210 Address: c.Config.Address, 211 Port: c.Config.Port, 212 Lifetime: c.Config.RecordLifetime, 213 }); err != nil { 214 log.Fatalf("failed to set rpki config: %s", err) 215 } 216 } 217 for _, c := range newConfig.BmpServers { 218 if err := bgpServer.AddBmp(context.Background(), &api.AddBmpRequest{ 219 Address: c.Config.Address, 220 Port: c.Config.Port, 221 Policy: api.AddBmpRequest_MonitoringPolicy(c.Config.RouteMonitoringPolicy.ToInt()), 222 StatisticsTimeout: int32(c.Config.StatisticsTimeout), 223 }); err != nil { 224 log.Fatalf("failed to set bmp config: %s", err) 225 } 226 } 227 for _, vrf := range newConfig.Vrfs { 228 rd, err := bgp.ParseRouteDistinguisher(vrf.Config.Rd) 229 if err != nil { 230 log.Fatalf("failed to load vrf rd config: %s", err) 231 } 232 233 importRtList, err := marshalRouteTargets(vrf.Config.ImportRtList) 234 if err != nil { 235 log.Fatalf("failed to load vrf import rt config: %s", err) 236 } 237 exportRtList, err := marshalRouteTargets(vrf.Config.ExportRtList) 238 if err != nil { 239 log.Fatalf("failed to load vrf export rt config: %s", err) 240 } 241 242 if err := bgpServer.AddVrf(context.Background(), &api.AddVrfRequest{ 243 Vrf: &api.Vrf{ 244 Name: vrf.Config.Name, 245 Rd: apiutil.MarshalRD(rd), 246 Id: uint32(vrf.Config.Id), 247 ImportRt: importRtList, 248 ExportRt: exportRtList, 249 }, 250 }); err != nil { 251 log.Fatalf("failed to set vrf config: %s", err) 252 } 253 } 254 for _, c := range newConfig.MrtDump { 255 if len(c.Config.FileName) == 0 { 256 continue 257 } 258 if err := bgpServer.EnableMrt(context.Background(), &api.EnableMrtRequest{ 259 DumpType: int32(c.Config.DumpType.ToInt()), 260 Filename: c.Config.FileName, 261 DumpInterval: c.Config.DumpInterval, 262 RotationInterval: c.Config.RotationInterval, 263 }); err != nil { 264 log.Fatalf("failed to set mrt config: %s", err) 265 } 266 } 267 p := config.ConfigSetToRoutingPolicy(newConfig) 268 rp, err := table.NewAPIRoutingPolicyFromConfigStruct(p) 269 if err != nil { 270 log.Warn(err) 271 } else { 272 bgpServer.SetPolicies(context.Background(), &api.SetPoliciesRequest{ 273 DefinedSets: rp.DefinedSets, 274 Policies: rp.Policies, 275 }) 276 } 277 278 added = newConfig.Neighbors 279 addedPg = newConfig.PeerGroups 280 if opts.GracefulRestart { 281 for i, n := range added { 282 if n.GracefulRestart.Config.Enabled { 283 added[i].GracefulRestart.State.LocalRestarting = true 284 } 285 } 286 } 287 288 } else { 289 addedPg, deletedPg, updatedPg = config.UpdatePeerGroupConfig(c, newConfig) 290 added, deleted, updated = config.UpdateNeighborConfig(c, newConfig) 291 updatePolicy = config.CheckPolicyDifference(config.ConfigSetToRoutingPolicy(c), config.ConfigSetToRoutingPolicy(newConfig)) 292 293 if updatePolicy { 294 log.Info("Policy config is updated") 295 p := config.ConfigSetToRoutingPolicy(newConfig) 296 rp, err := table.NewAPIRoutingPolicyFromConfigStruct(p) 297 if err != nil { 298 log.Warn(err) 299 } else { 300 bgpServer.SetPolicies(context.Background(), &api.SetPoliciesRequest{ 301 DefinedSets: rp.DefinedSets, 302 Policies: rp.Policies, 303 }) 304 } 305 } 306 // global policy update 307 if !newConfig.Global.ApplyPolicy.Config.Equal(&c.Global.ApplyPolicy.Config) { 308 a := newConfig.Global.ApplyPolicy.Config 309 toDefaultTable := func(r config.DefaultPolicyType) table.RouteType { 310 var def table.RouteType 311 switch r { 312 case config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE: 313 def = table.ROUTE_TYPE_ACCEPT 314 case config.DEFAULT_POLICY_TYPE_REJECT_ROUTE: 315 def = table.ROUTE_TYPE_REJECT 316 } 317 return def 318 } 319 toPolicies := func(r []string) []*table.Policy { 320 p := make([]*table.Policy, 0, len(r)) 321 for _, n := range r { 322 p = append(p, &table.Policy{ 323 Name: n, 324 }) 325 } 326 return p 327 } 328 329 def := toDefaultTable(a.DefaultImportPolicy) 330 ps := toPolicies(a.ImportPolicyList) 331 bgpServer.SetPolicyAssignment(context.Background(), &api.SetPolicyAssignmentRequest{ 332 Assignment: table.NewAPIPolicyAssignmentFromTableStruct(&table.PolicyAssignment{ 333 Name: table.GLOBAL_RIB_NAME, 334 Type: table.POLICY_DIRECTION_IMPORT, 335 Policies: ps, 336 Default: def, 337 }), 338 }) 339 340 def = toDefaultTable(a.DefaultExportPolicy) 341 ps = toPolicies(a.ExportPolicyList) 342 bgpServer.SetPolicyAssignment(context.Background(), &api.SetPolicyAssignmentRequest{ 343 Assignment: table.NewAPIPolicyAssignmentFromTableStruct(&table.PolicyAssignment{ 344 Name: table.GLOBAL_RIB_NAME, 345 Type: table.POLICY_DIRECTION_EXPORT, 346 Policies: ps, 347 Default: def, 348 }), 349 }) 350 351 updatePolicy = true 352 353 } 354 c = newConfig 355 } 356 for _, pg := range addedPg { 357 log.Infof("PeerGroup %s is added", pg.Config.PeerGroupName) 358 if err := bgpServer.AddPeerGroup(context.Background(), &api.AddPeerGroupRequest{ 359 PeerGroup: config.NewPeerGroupFromConfigStruct(&pg), 360 }); err != nil { 361 log.Warn(err) 362 } 363 } 364 for _, pg := range deletedPg { 365 log.Infof("PeerGroup %s is deleted", pg.Config.PeerGroupName) 366 if err := bgpServer.DeletePeerGroup(context.Background(), &api.DeletePeerGroupRequest{ 367 Name: pg.Config.PeerGroupName, 368 }); err != nil { 369 log.Warn(err) 370 } 371 } 372 for _, pg := range updatedPg { 373 log.Infof("PeerGroup %v is updated", pg.State.PeerGroupName) 374 if u, err := bgpServer.UpdatePeerGroup(context.Background(), &api.UpdatePeerGroupRequest{ 375 PeerGroup: config.NewPeerGroupFromConfigStruct(&pg), 376 }); err != nil { 377 log.Warn(err) 378 } else { 379 updatePolicy = updatePolicy || u.NeedsSoftResetIn 380 } 381 } 382 for _, pg := range updatedPg { 383 log.Infof("PeerGroup %s is updated", pg.Config.PeerGroupName) 384 if _, err := bgpServer.UpdatePeerGroup(context.Background(), &api.UpdatePeerGroupRequest{ 385 PeerGroup: config.NewPeerGroupFromConfigStruct(&pg), 386 }); err != nil { 387 log.Warn(err) 388 } 389 } 390 for _, dn := range newConfig.DynamicNeighbors { 391 log.Infof("Dynamic Neighbor %s is added to PeerGroup %s", dn.Config.Prefix, dn.Config.PeerGroup) 392 if err := bgpServer.AddDynamicNeighbor(context.Background(), &api.AddDynamicNeighborRequest{ 393 DynamicNeighbor: &api.DynamicNeighbor{ 394 Prefix: dn.Config.Prefix, 395 PeerGroup: dn.Config.PeerGroup, 396 }, 397 }); err != nil { 398 log.Warn(err) 399 } 400 } 401 for _, p := range added { 402 log.Infof("Peer %v is added", p.State.NeighborAddress) 403 if err := bgpServer.AddPeer(context.Background(), &api.AddPeerRequest{ 404 Peer: config.NewPeerFromConfigStruct(&p), 405 }); err != nil { 406 log.Warn(err) 407 } 408 } 409 for _, p := range deleted { 410 log.Infof("Peer %v is deleted", p.State.NeighborAddress) 411 if err := bgpServer.DeletePeer(context.Background(), &api.DeletePeerRequest{ 412 Address: p.State.NeighborAddress, 413 }); err != nil { 414 log.Warn(err) 415 } 416 } 417 for _, p := range updated { 418 log.Infof("Peer %v is updated", p.State.NeighborAddress) 419 if u, err := bgpServer.UpdatePeer(context.Background(), &api.UpdatePeerRequest{ 420 Peer: config.NewPeerFromConfigStruct(&p), 421 }); err != nil { 422 log.Warn(err) 423 } else { 424 updatePolicy = updatePolicy || u.NeedsSoftResetIn 425 } 426 } 427 428 if updatePolicy { 429 if err := bgpServer.ResetPeer(context.Background(), &api.ResetPeerRequest{ 430 Address: "", 431 Direction: api.ResetPeerRequest_IN, 432 Soft: true, 433 }); err != nil { 434 log.Warn(err) 435 } 436 } 437 } 438 } 439 } 440 441 loop() 442 }