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 }