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  }