github.com/cilium/cilium@v1.16.2/pkg/bgpv1/gobgp/state.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package gobgp
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  
    10  	gobgp "github.com/osrg/gobgp/v3/api"
    11  
    12  	"github.com/cilium/cilium/api/v1/models"
    13  	"github.com/cilium/cilium/pkg/bgpv1/types"
    14  	v2alpha1api "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2alpha1"
    15  	"github.com/cilium/cilium/pkg/time"
    16  )
    17  
    18  // GetBgp returns bgp global configuration from gobgp server
    19  func (g *GoBGPServer) GetBGP(ctx context.Context) (types.GetBGPResponse, error) {
    20  	bgpConfig, err := g.server.GetBgp(ctx, &gobgp.GetBgpRequest{})
    21  	if err != nil {
    22  		return types.GetBGPResponse{}, err
    23  	}
    24  
    25  	if bgpConfig.Global == nil {
    26  		return types.GetBGPResponse{}, fmt.Errorf("gobgp returned nil config")
    27  	}
    28  
    29  	res := types.BGPGlobal{
    30  		ASN:        bgpConfig.Global.Asn,
    31  		RouterID:   bgpConfig.Global.RouterId,
    32  		ListenPort: bgpConfig.Global.ListenPort,
    33  	}
    34  	if bgpConfig.Global.RouteSelectionOptions != nil {
    35  		res.RouteSelectionOptions = &types.RouteSelectionOptions{
    36  			AdvertiseInactiveRoutes: bgpConfig.Global.RouteSelectionOptions.AdvertiseInactiveRoutes,
    37  		}
    38  	}
    39  
    40  	return types.GetBGPResponse{
    41  		Global: res,
    42  	}, nil
    43  }
    44  
    45  // GetPeerState invokes goBGP ListPeer API to get current peering state.
    46  func (g *GoBGPServer) GetPeerState(ctx context.Context) (types.GetPeerStateResponse, error) {
    47  	var data []*models.BgpPeer
    48  	fn := func(peer *gobgp.Peer) {
    49  		if peer == nil {
    50  			return
    51  		}
    52  
    53  		peerState := &models.BgpPeer{}
    54  
    55  		if peer.Transport != nil {
    56  			peerState.PeerPort = int64(peer.Transport.RemotePort)
    57  		}
    58  
    59  		if peer.Conf != nil {
    60  			peerState.LocalAsn = int64(peer.Conf.LocalAsn)
    61  			peerState.PeerAddress = peer.Conf.NeighborAddress
    62  			peerState.PeerAsn = int64(peer.Conf.PeerAsn)
    63  			peerState.TCPPasswordEnabled = peer.Conf.AuthPassword != ""
    64  		}
    65  
    66  		if peer.State != nil {
    67  			peerState.SessionState = toAgentSessionState(peer.State.SessionState).String()
    68  
    69  			// Uptime is time since session got established.
    70  			// It is calculated by difference in time from uptime timestamp till now.
    71  			if peer.State.SessionState == gobgp.PeerState_ESTABLISHED && peer.Timers != nil && peer.Timers.State != nil {
    72  				peerState.UptimeNanoseconds = int64(time.Since(peer.Timers.State.Uptime.AsTime()))
    73  			}
    74  		}
    75  
    76  		for _, afiSafi := range peer.AfiSafis {
    77  			if afiSafi.State == nil {
    78  				continue
    79  			}
    80  			peerState.Families = append(peerState.Families, toAgentAfiSafiState(afiSafi.State))
    81  		}
    82  
    83  		if peer.EbgpMultihop != nil && peer.EbgpMultihop.Enabled {
    84  			peerState.EbgpMultihopTTL = int64(peer.EbgpMultihop.MultihopTtl)
    85  		} else {
    86  			peerState.EbgpMultihopTTL = int64(v2alpha1api.DefaultBGPEBGPMultihopTTL) // defaults to 1 if not enabled
    87  		}
    88  
    89  		if peer.Timers != nil {
    90  			tConfig := peer.Timers.Config
    91  			tState := peer.Timers.State
    92  			if tConfig != nil {
    93  				peerState.ConnectRetryTimeSeconds = int64(tConfig.ConnectRetry)
    94  				peerState.ConfiguredHoldTimeSeconds = int64(tConfig.HoldTime)
    95  				peerState.ConfiguredKeepAliveTimeSeconds = int64(tConfig.KeepaliveInterval)
    96  			}
    97  			if tState != nil {
    98  				if tState.NegotiatedHoldTime != 0 {
    99  					peerState.AppliedHoldTimeSeconds = int64(tState.NegotiatedHoldTime)
   100  				}
   101  				if tState.KeepaliveInterval != 0 {
   102  					peerState.AppliedKeepAliveTimeSeconds = int64(tState.KeepaliveInterval)
   103  				}
   104  			}
   105  		}
   106  
   107  		peerState.GracefulRestart = &models.BgpGracefulRestart{}
   108  		if peer.GracefulRestart != nil {
   109  			peerState.GracefulRestart.Enabled = peer.GracefulRestart.Enabled
   110  			peerState.GracefulRestart.RestartTimeSeconds = int64(peer.GracefulRestart.RestartTime)
   111  		}
   112  
   113  		data = append(data, peerState)
   114  	}
   115  
   116  	// API to get peering list from gobgp, enableAdvertised is set to true to get count of
   117  	// advertised routes.
   118  	err := g.server.ListPeer(ctx, &gobgp.ListPeerRequest{EnableAdvertised: true}, fn)
   119  	if err != nil {
   120  		return types.GetPeerStateResponse{}, err
   121  	}
   122  
   123  	return types.GetPeerStateResponse{
   124  		Peers: data,
   125  	}, nil
   126  }
   127  
   128  // toAgentAfiSafiState translates gobgp structures to cilium bgp models.
   129  func toAgentAfiSafiState(state *gobgp.AfiSafiState) *models.BgpPeerFamilies {
   130  	res := &models.BgpPeerFamilies{}
   131  
   132  	if state.Family != nil {
   133  		res.Afi = toAgentAfi(state.Family.Afi).String()
   134  		res.Safi = toAgentSafi(state.Family.Safi).String()
   135  	}
   136  
   137  	res.Received = int64(state.Received)
   138  	res.Accepted = int64(state.Accepted)
   139  	res.Advertised = int64(state.Advertised)
   140  
   141  	return res
   142  }
   143  
   144  // GetRoutes retrieves routes from the RIB of underlying router
   145  func (g *GoBGPServer) GetRoutes(ctx context.Context, r *types.GetRoutesRequest) (*types.GetRoutesResponse, error) {
   146  	errs := []error{}
   147  	var routes []*types.Route
   148  
   149  	fn := func(destination *gobgp.Destination) {
   150  		paths, err := ToAgentPaths(destination.Paths)
   151  		if err != nil {
   152  			errs = append(errs, err)
   153  			return
   154  		}
   155  		routes = append(routes, &types.Route{
   156  			Prefix: destination.Prefix,
   157  			Paths:  paths,
   158  		})
   159  	}
   160  
   161  	tt, err := toGoBGPTableType(r.TableType)
   162  	if err != nil {
   163  		return nil, fmt.Errorf("invalid table type: %w", err)
   164  	}
   165  
   166  	family := &gobgp.Family{
   167  		Afi:  gobgp.Family_Afi(r.Family.Afi),
   168  		Safi: gobgp.Family_Safi(r.Family.Safi),
   169  	}
   170  
   171  	var neighbor string
   172  	if r.Neighbor.IsValid() {
   173  		neighbor = r.Neighbor.String()
   174  	}
   175  
   176  	req := &gobgp.ListPathRequest{
   177  		TableType: tt,
   178  		Family:    family,
   179  		Name:      neighbor,
   180  	}
   181  
   182  	if err := g.server.ListPath(ctx, req, fn); err != nil {
   183  		return nil, err
   184  	}
   185  
   186  	return &types.GetRoutesResponse{
   187  		Routes: routes,
   188  	}, nil
   189  }
   190  
   191  // GetRoutePolicies retrieves route policies from the underlying router
   192  func (g *GoBGPServer) GetRoutePolicies(ctx context.Context) (*types.GetRoutePoliciesResponse, error) {
   193  	// list defined sets into a map for later use
   194  	definedSets := make(map[string]*gobgp.DefinedSet)
   195  	err := g.server.ListDefinedSet(ctx, &gobgp.ListDefinedSetRequest{DefinedType: gobgp.DefinedType_NEIGHBOR}, func(ds *gobgp.DefinedSet) {
   196  		definedSets[ds.Name] = ds
   197  	})
   198  	if err != nil {
   199  		return nil, fmt.Errorf("failed listing neighbor defined sets: %w", err)
   200  	}
   201  	err = g.server.ListDefinedSet(ctx, &gobgp.ListDefinedSetRequest{DefinedType: gobgp.DefinedType_PREFIX}, func(ds *gobgp.DefinedSet) {
   202  		definedSets[ds.Name] = ds
   203  	})
   204  	if err != nil {
   205  		return nil, fmt.Errorf("failed listing prefix defined sets: %w", err)
   206  	}
   207  
   208  	// list policy assignments into a map for later use
   209  	assignments := make(map[string]*gobgp.PolicyAssignment)
   210  	err = g.server.ListPolicyAssignment(ctx, &gobgp.ListPolicyAssignmentRequest{}, func(a *gobgp.PolicyAssignment) {
   211  		for _, p := range a.Policies {
   212  			assignments[p.Name] = a
   213  		}
   214  	})
   215  	if err != nil {
   216  		return nil, fmt.Errorf("failed listing policy assignments: %w", err)
   217  	}
   218  
   219  	// list & convert policies
   220  	var policies []*types.RoutePolicy
   221  	err = g.server.ListPolicy(ctx, &gobgp.ListPolicyRequest{}, func(p *gobgp.Policy) {
   222  		// process only assigned policies
   223  		if assignment, exists := assignments[p.Name]; exists {
   224  			policies = append(policies, toAgentPolicy(p, definedSets, assignment))
   225  		}
   226  	})
   227  	if err != nil {
   228  		return nil, fmt.Errorf("failed listing route policies: %w", err)
   229  	}
   230  
   231  	return &types.GetRoutePoliciesResponse{
   232  		Policies: policies,
   233  	}, nil
   234  }