github.com/osrg/gobgp/v3@v3.30.0/pkg/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"context"
     5  
     6  	apb "google.golang.org/protobuf/types/known/anypb"
     7  
     8  	api "github.com/osrg/gobgp/v3/api"
     9  	"github.com/osrg/gobgp/v3/internal/pkg/table"
    10  	"github.com/osrg/gobgp/v3/pkg/apiutil"
    11  	"github.com/osrg/gobgp/v3/pkg/config/oc"
    12  	"github.com/osrg/gobgp/v3/pkg/log"
    13  	"github.com/osrg/gobgp/v3/pkg/packet/bgp"
    14  	"github.com/osrg/gobgp/v3/pkg/server"
    15  )
    16  
    17  // ReadConfigFile parses a config file into a BgpConfigSet which can be applied
    18  // using InitialConfig and UpdateConfig.
    19  func ReadConfigFile(configFile, configType string) (*oc.BgpConfigSet, error) {
    20  	return oc.ReadConfigfile(configFile, configType)
    21  }
    22  
    23  // WatchConfigFile calls the callback function anytime an update to the
    24  // config file is detected.
    25  func WatchConfigFile(configFile, configType string, callBack func()) {
    26  	oc.WatchConfigFile(configFile, configType, callBack)
    27  }
    28  
    29  func marshalRouteTargets(l []string) ([]*apb.Any, error) {
    30  	rtList := make([]*apb.Any, 0, len(l))
    31  	for _, rtString := range l {
    32  		rt, err := bgp.ParseRouteTarget(rtString)
    33  		if err != nil {
    34  			return nil, err
    35  		}
    36  		a, err := apiutil.MarshalRT(rt)
    37  		if err != nil {
    38  			return nil, err
    39  		}
    40  		rtList = append(rtList, a)
    41  	}
    42  	return rtList, nil
    43  }
    44  
    45  func assignGlobalpolicy(ctx context.Context, bgpServer *server.BgpServer, a *oc.ApplyPolicyConfig) {
    46  	toDefaultTable := func(r oc.DefaultPolicyType) table.RouteType {
    47  		var def table.RouteType
    48  		switch r {
    49  		case oc.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE:
    50  			def = table.ROUTE_TYPE_ACCEPT
    51  		case oc.DEFAULT_POLICY_TYPE_REJECT_ROUTE:
    52  			def = table.ROUTE_TYPE_REJECT
    53  		}
    54  		return def
    55  	}
    56  	toPolicies := func(r []string) []*table.Policy {
    57  		p := make([]*table.Policy, 0, len(r))
    58  		for _, n := range r {
    59  			p = append(p, &table.Policy{
    60  				Name: n,
    61  			})
    62  		}
    63  		return p
    64  	}
    65  
    66  	def := toDefaultTable(a.DefaultImportPolicy)
    67  	ps := toPolicies(a.ImportPolicyList)
    68  	bgpServer.SetPolicyAssignment(ctx, &api.SetPolicyAssignmentRequest{
    69  		Assignment: table.NewAPIPolicyAssignmentFromTableStruct(&table.PolicyAssignment{
    70  			Name:     table.GLOBAL_RIB_NAME,
    71  			Type:     table.POLICY_DIRECTION_IMPORT,
    72  			Policies: ps,
    73  			Default:  def,
    74  		}),
    75  	})
    76  
    77  	def = toDefaultTable(a.DefaultExportPolicy)
    78  	ps = toPolicies(a.ExportPolicyList)
    79  	bgpServer.SetPolicyAssignment(ctx, &api.SetPolicyAssignmentRequest{
    80  		Assignment: table.NewAPIPolicyAssignmentFromTableStruct(&table.PolicyAssignment{
    81  			Name:     table.GLOBAL_RIB_NAME,
    82  			Type:     table.POLICY_DIRECTION_EXPORT,
    83  			Policies: ps,
    84  			Default:  def,
    85  		}),
    86  	})
    87  
    88  }
    89  
    90  func addPeerGroups(ctx context.Context, bgpServer *server.BgpServer, addedPg []oc.PeerGroup) {
    91  	for _, pg := range addedPg {
    92  		bgpServer.Log().Info("Add PeerGroup",
    93  			log.Fields{
    94  				"Topic": "config",
    95  				"Key":   pg.Config.PeerGroupName,
    96  			})
    97  
    98  		if err := bgpServer.AddPeerGroup(ctx, &api.AddPeerGroupRequest{
    99  			PeerGroup: oc.NewPeerGroupFromConfigStruct(&pg),
   100  		}); err != nil {
   101  			bgpServer.Log().Warn("Failed to add PeerGroup",
   102  				log.Fields{
   103  					"Topic": "config",
   104  					"Key":   pg.Config.PeerGroupName,
   105  					"Error": err})
   106  		}
   107  	}
   108  }
   109  
   110  func deletePeerGroups(ctx context.Context, bgpServer *server.BgpServer, deletedPg []oc.PeerGroup) {
   111  	for _, pg := range deletedPg {
   112  		bgpServer.Log().Info("delete PeerGroup",
   113  			log.Fields{
   114  				"Topic": "config",
   115  				"Key":   pg.Config.PeerGroupName})
   116  		if err := bgpServer.DeletePeerGroup(ctx, &api.DeletePeerGroupRequest{
   117  			Name: pg.Config.PeerGroupName,
   118  		}); err != nil {
   119  			bgpServer.Log().Warn("Failed to delete PeerGroup",
   120  				log.Fields{
   121  					"Topic": "config",
   122  					"Key":   pg.Config.PeerGroupName,
   123  					"Error": err})
   124  		}
   125  	}
   126  }
   127  
   128  func updatePeerGroups(ctx context.Context, bgpServer *server.BgpServer, updatedPg []oc.PeerGroup) bool {
   129  	for _, pg := range updatedPg {
   130  		bgpServer.Log().Info("update PeerGroup",
   131  			log.Fields{
   132  				"Topic": "config",
   133  				"Key":   pg.Config.PeerGroupName})
   134  		if u, err := bgpServer.UpdatePeerGroup(ctx, &api.UpdatePeerGroupRequest{
   135  			PeerGroup: oc.NewPeerGroupFromConfigStruct(&pg),
   136  		}); err != nil {
   137  			bgpServer.Log().Warn("Failed to update PeerGroup",
   138  				log.Fields{
   139  					"Topic": "config",
   140  					"Key":   pg.Config.PeerGroupName,
   141  					"Error": err})
   142  		} else {
   143  			return u.NeedsSoftResetIn
   144  		}
   145  	}
   146  	return false
   147  }
   148  
   149  func addDynamicNeighbors(ctx context.Context, bgpServer *server.BgpServer, dynamicNeighbors []oc.DynamicNeighbor) {
   150  	for _, dn := range dynamicNeighbors {
   151  		bgpServer.Log().Info("Add Dynamic Neighbor to PeerGroup",
   152  			log.Fields{
   153  				"Topic":  "config",
   154  				"Key":    dn.Config.PeerGroup,
   155  				"Prefix": dn.Config.Prefix})
   156  		if err := bgpServer.AddDynamicNeighbor(ctx, &api.AddDynamicNeighborRequest{
   157  			DynamicNeighbor: &api.DynamicNeighbor{
   158  				Prefix:    dn.Config.Prefix,
   159  				PeerGroup: dn.Config.PeerGroup,
   160  			},
   161  		}); err != nil {
   162  			bgpServer.Log().Warn("Failed to add Dynamic Neighbor to PeerGroup",
   163  				log.Fields{
   164  					"Topic":  "config",
   165  					"Key":    dn.Config.PeerGroup,
   166  					"Prefix": dn.Config.Prefix,
   167  					"Error":  err})
   168  		}
   169  	}
   170  }
   171  
   172  func addNeighbors(ctx context.Context, bgpServer *server.BgpServer, added []oc.Neighbor) {
   173  	for _, p := range added {
   174  		bgpServer.Log().Info("Add Peer",
   175  			log.Fields{
   176  				"Topic": "config",
   177  				"Key":   p.State.NeighborAddress})
   178  		if err := bgpServer.AddPeer(ctx, &api.AddPeerRequest{
   179  			Peer: oc.NewPeerFromConfigStruct(&p),
   180  		}); err != nil {
   181  			bgpServer.Log().Warn("Failed to add Peer",
   182  				log.Fields{
   183  					"Topic": "config",
   184  					"Key":   p.State.NeighborAddress,
   185  					"Error": err})
   186  		}
   187  	}
   188  }
   189  
   190  func deleteNeighbors(ctx context.Context, bgpServer *server.BgpServer, deleted []oc.Neighbor) {
   191  	for _, p := range deleted {
   192  		bgpServer.Log().Info("Delete Peer",
   193  			log.Fields{
   194  				"Topic": "config",
   195  				"Key":   p.State.NeighborAddress})
   196  		if err := bgpServer.DeletePeer(ctx, &api.DeletePeerRequest{
   197  			Address: p.State.NeighborAddress,
   198  		}); err != nil {
   199  			bgpServer.Log().Warn("Failed to delete Peer",
   200  				log.Fields{
   201  					"Topic": "config",
   202  					"Key":   p.State.NeighborAddress,
   203  					"Error": err})
   204  		}
   205  	}
   206  }
   207  
   208  func updateNeighbors(ctx context.Context, bgpServer *server.BgpServer, updated []oc.Neighbor) bool {
   209  	for _, p := range updated {
   210  		bgpServer.Log().Info("Update Peer",
   211  			log.Fields{
   212  				"Topic": "config",
   213  				"Key":   p.State.NeighborAddress})
   214  		if u, err := bgpServer.UpdatePeer(ctx, &api.UpdatePeerRequest{
   215  			Peer: oc.NewPeerFromConfigStruct(&p),
   216  		}); err != nil {
   217  			bgpServer.Log().Warn("Failed to update Peer",
   218  				log.Fields{
   219  					"Topic": "config",
   220  					"Key":   p.State.NeighborAddress,
   221  					"Error": err})
   222  		} else {
   223  			return u.NeedsSoftResetIn
   224  		}
   225  	}
   226  	return false
   227  }
   228  
   229  // InitialConfig applies initial configuration to a pristine gobgp instance. It
   230  // can only be called once for an instance. Subsequent changes to the
   231  // configuration can be applied using UpdateConfig. The BgpConfigSet can be
   232  // obtained by calling ReadConfigFile. If graceful restart behavior is desired,
   233  // pass true for isGracefulRestart. Otherwise, pass false.
   234  func InitialConfig(ctx context.Context, bgpServer *server.BgpServer, newConfig *oc.BgpConfigSet, isGracefulRestart bool) (*oc.BgpConfigSet, error) {
   235  	if err := bgpServer.StartBgp(ctx, &api.StartBgpRequest{
   236  		Global: oc.NewGlobalFromConfigStruct(&newConfig.Global),
   237  	}); err != nil {
   238  		bgpServer.Log().Fatal("failed to set global config",
   239  			log.Fields{"Topic": "config", "Error": err})
   240  	}
   241  
   242  	if newConfig.Zebra.Config.Enabled {
   243  		tps := newConfig.Zebra.Config.RedistributeRouteTypeList
   244  		l := make([]string, 0, len(tps))
   245  		l = append(l, tps...)
   246  		if err := bgpServer.EnableZebra(ctx, &api.EnableZebraRequest{
   247  			Url:                  newConfig.Zebra.Config.Url,
   248  			RouteTypes:           l,
   249  			Version:              uint32(newConfig.Zebra.Config.Version),
   250  			NexthopTriggerEnable: newConfig.Zebra.Config.NexthopTriggerEnable,
   251  			NexthopTriggerDelay:  uint32(newConfig.Zebra.Config.NexthopTriggerDelay),
   252  			MplsLabelRangeSize:   uint32(newConfig.Zebra.Config.MplsLabelRangeSize),
   253  			SoftwareName:         newConfig.Zebra.Config.SoftwareName,
   254  		}); err != nil {
   255  			bgpServer.Log().Fatal("failed to set zebra config",
   256  				log.Fields{"Topic": "config", "Error": err})
   257  		}
   258  	}
   259  
   260  	if len(newConfig.Collector.Config.Url) > 0 {
   261  		bgpServer.Log().Fatal("collector feature is not supported",
   262  			log.Fields{"Topic": "config"})
   263  	}
   264  
   265  	for _, c := range newConfig.RpkiServers {
   266  		if err := bgpServer.AddRpki(ctx, &api.AddRpkiRequest{
   267  			Address:  c.Config.Address,
   268  			Port:     c.Config.Port,
   269  			Lifetime: c.Config.RecordLifetime,
   270  		}); err != nil {
   271  			bgpServer.Log().Fatal("failed to set rpki config",
   272  				log.Fields{"Topic": "config", "Error": err})
   273  		}
   274  	}
   275  	for _, c := range newConfig.BmpServers {
   276  		if err := bgpServer.AddBmp(ctx, &api.AddBmpRequest{
   277  			Address:           c.Config.Address,
   278  			Port:              c.Config.Port,
   279  			SysName:           c.Config.SysName,
   280  			SysDescr:          c.Config.SysDescr,
   281  			Policy:            api.AddBmpRequest_MonitoringPolicy(c.Config.RouteMonitoringPolicy.ToInt()),
   282  			StatisticsTimeout: int32(c.Config.StatisticsTimeout),
   283  		}); err != nil {
   284  			bgpServer.Log().Fatal("failed to set bmp config",
   285  				log.Fields{"Topic": "config", "Error": err})
   286  		}
   287  	}
   288  	for _, vrf := range newConfig.Vrfs {
   289  		rd, err := bgp.ParseRouteDistinguisher(vrf.Config.Rd)
   290  		if err != nil {
   291  			bgpServer.Log().Fatal("failed to load vrf rd config",
   292  				log.Fields{"Topic": "config", "Error": err})
   293  		}
   294  
   295  		importRtList, err := marshalRouteTargets(vrf.Config.ImportRtList)
   296  		if err != nil {
   297  			bgpServer.Log().Fatal("failed to load vrf import rt config",
   298  				log.Fields{"Topic": "config", "Error": err})
   299  		}
   300  		exportRtList, err := marshalRouteTargets(vrf.Config.ExportRtList)
   301  		if err != nil {
   302  			bgpServer.Log().Fatal("failed to load vrf export rt config",
   303  				log.Fields{"Topic": "config", "Error": err})
   304  		}
   305  
   306  		a, err := apiutil.MarshalRD(rd)
   307  		if err != nil {
   308  			bgpServer.Log().Fatal("failed to set vrf config",
   309  				log.Fields{"Topic": "config", "Error": err})
   310  		}
   311  		if err := bgpServer.AddVrf(ctx, &api.AddVrfRequest{
   312  			Vrf: &api.Vrf{
   313  				Name:     vrf.Config.Name,
   314  				Rd:       a,
   315  				Id:       uint32(vrf.Config.Id),
   316  				ImportRt: importRtList,
   317  				ExportRt: exportRtList,
   318  			},
   319  		}); err != nil {
   320  			bgpServer.Log().Fatal("failed to set vrf config",
   321  				log.Fields{"Topic": "config", "Error": err})
   322  		}
   323  	}
   324  	for _, c := range newConfig.MrtDump {
   325  		if len(c.Config.FileName) == 0 {
   326  			continue
   327  		}
   328  		if err := bgpServer.EnableMrt(ctx, &api.EnableMrtRequest{
   329  			Type:             api.EnableMrtRequest_DumpType(c.Config.DumpType.ToInt()),
   330  			Filename:         c.Config.FileName,
   331  			DumpInterval:     c.Config.DumpInterval,
   332  			RotationInterval: c.Config.RotationInterval,
   333  		}); err != nil {
   334  			bgpServer.Log().Fatal("failed to set mrt config",
   335  				log.Fields{"Topic": "config", "Error": err})
   336  		}
   337  	}
   338  	p := oc.ConfigSetToRoutingPolicy(newConfig)
   339  	rp, err := table.NewAPIRoutingPolicyFromConfigStruct(p)
   340  	if err != nil {
   341  		bgpServer.Log().Fatal("failed to update policy config",
   342  			log.Fields{"Topic": "config", "Error": err})
   343  	} else {
   344  		bgpServer.SetPolicies(ctx, &api.SetPoliciesRequest{
   345  			DefinedSets: rp.DefinedSets,
   346  			Policies:    rp.Policies,
   347  		})
   348  	}
   349  
   350  	assignGlobalpolicy(ctx, bgpServer, &newConfig.Global.ApplyPolicy.Config)
   351  
   352  	added := newConfig.Neighbors
   353  	addedPg := newConfig.PeerGroups
   354  	if isGracefulRestart {
   355  		for i, n := range added {
   356  			if n.GracefulRestart.Config.Enabled {
   357  				added[i].GracefulRestart.State.LocalRestarting = true
   358  			}
   359  		}
   360  	}
   361  
   362  	addPeerGroups(ctx, bgpServer, addedPg)
   363  	addDynamicNeighbors(ctx, bgpServer, newConfig.DynamicNeighbors)
   364  	addNeighbors(ctx, bgpServer, added)
   365  	return newConfig, nil
   366  }
   367  
   368  // UpdateConfig updates the configuration of a running gobgp instance.
   369  // InitialConfig must have been called once before this can be called for
   370  // subsequent changes to config. The differences are that this call 1) does not
   371  // hangle graceful restart and 2) requires a BgpConfigSet for the previous
   372  // configuration so that it can compute the delta between it and the new
   373  // config. The new BgpConfigSet can be obtained using ReadConfigFile.
   374  func UpdateConfig(ctx context.Context, bgpServer *server.BgpServer, c, newConfig *oc.BgpConfigSet) (*oc.BgpConfigSet, error) {
   375  	addedPg, deletedPg, updatedPg := oc.UpdatePeerGroupConfig(bgpServer.Log(), c, newConfig)
   376  	added, deleted, updated := oc.UpdateNeighborConfig(bgpServer.Log(), c, newConfig)
   377  	updatePolicy := oc.CheckPolicyDifference(bgpServer.Log(), oc.ConfigSetToRoutingPolicy(c), oc.ConfigSetToRoutingPolicy(newConfig))
   378  
   379  	if updatePolicy {
   380  		bgpServer.Log().Info("policy config is update", log.Fields{"Topic": "config"})
   381  		p := oc.ConfigSetToRoutingPolicy(newConfig)
   382  		rp, err := table.NewAPIRoutingPolicyFromConfigStruct(p)
   383  		if err != nil {
   384  			bgpServer.Log().Warn("failed to update policy config",
   385  				log.Fields{
   386  					"Topic": "config",
   387  					"Error": err})
   388  		} else {
   389  			bgpServer.SetPolicies(ctx, &api.SetPoliciesRequest{
   390  				DefinedSets: rp.DefinedSets,
   391  				Policies:    rp.Policies,
   392  			})
   393  		}
   394  	}
   395  	// global policy update
   396  	if !newConfig.Global.ApplyPolicy.Config.Equal(&c.Global.ApplyPolicy.Config) {
   397  		assignGlobalpolicy(ctx, bgpServer, &newConfig.Global.ApplyPolicy.Config)
   398  		updatePolicy = true
   399  	}
   400  
   401  	addPeerGroups(ctx, bgpServer, addedPg)
   402  	deletePeerGroups(ctx, bgpServer, deletedPg)
   403  	needsSoftResetIn := updatePeerGroups(ctx, bgpServer, updatedPg)
   404  	updatePolicy = updatePolicy || needsSoftResetIn
   405  	addDynamicNeighbors(ctx, bgpServer, newConfig.DynamicNeighbors)
   406  	addNeighbors(ctx, bgpServer, added)
   407  	deleteNeighbors(ctx, bgpServer, deleted)
   408  	needsSoftResetIn = updateNeighbors(ctx, bgpServer, updated)
   409  	updatePolicy = updatePolicy || needsSoftResetIn
   410  
   411  	if updatePolicy {
   412  		if err := bgpServer.ResetPeer(ctx, &api.ResetPeerRequest{
   413  			Address:   "",
   414  			Direction: api.ResetPeerRequest_IN,
   415  			Soft:      true,
   416  		}); err != nil {
   417  			bgpServer.Log().Fatal("failed to update policy config",
   418  				log.Fields{"Topic": "config", "Error": err})
   419  		}
   420  	}
   421  	return newConfig, nil
   422  }