github.com/cilium/cilium@v1.16.2/pkg/bgpv1/manager/reconciler/advertisements.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package reconciler 5 6 import ( 7 "context" 8 "fmt" 9 10 "github.com/sirupsen/logrus" 11 12 "github.com/cilium/cilium/pkg/bgpv1/manager/instance" 13 "github.com/cilium/cilium/pkg/bgpv1/types" 14 v2alpha1api "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2alpha1" 15 ) 16 17 type advertisementsReconcilerParams struct { 18 ctx context.Context 19 name string 20 component string 21 enabled bool 22 23 sc *instance.ServerWithConfig 24 newc *v2alpha1api.CiliumBGPVirtualRouter 25 26 currentAdvertisements []*types.Path 27 toAdvertise []*types.Path 28 } 29 30 // exportAdvertisementsReconciler reconciles the state of the BGP advertisements 31 // with the provided toAdvertise list and returns a list of the advertisements 32 // currently being announced. 33 func exportAdvertisementsReconciler(params *advertisementsReconcilerParams) ([]*types.Path, error) { 34 var ( 35 l = log.WithFields( 36 logrus.Fields{ 37 "component": params.component, 38 }, 39 ) 40 // holds advertisements which must be advertised 41 toAdvertise []*types.Path 42 // holds advertisements which must remain in place 43 toKeep []*types.Path 44 // holds advertisements which must be removed 45 toWithdraw []*types.Path 46 // the result of advertising toAdvertise. 47 newAdverts []*types.Path 48 ) 49 50 l.Debugf("Begin reconciling %s advertisements for virtual router with local ASN %v", params.name, params.newc.LocalASN) 51 52 // if advertisement is turned off withdraw any previously advertised 53 // cidrs and early return nil. 54 if !params.enabled { 55 l.Debugf("%s advertisements disabled for virtual router with local ASN %v", params.name, params.newc.LocalASN) 56 57 for _, advrt := range params.currentAdvertisements { 58 l.Debugf("Withdrawing %s advertisement %v for local ASN %v", params.name, advrt.NLRI, params.newc.LocalASN) 59 if err := params.sc.Server.WithdrawPath(params.ctx, types.PathRequest{Path: advrt}); err != nil { 60 return nil, err 61 } 62 } 63 64 return nil, nil 65 } 66 67 // an aset member which book keeps which universe it exists in 68 type member struct { 69 a bool 70 b bool 71 advrt *types.Path 72 } 73 74 aset := map[string]*member{} 75 76 // populate the advrts that must be present, universe a 77 for _, path := range params.toAdvertise { 78 var ( 79 m *member 80 ok bool 81 ) 82 83 key := path.NLRI.String() 84 if m, ok = aset[key]; !ok { 85 aset[key] = &member{ 86 a: true, 87 advrt: path, 88 } 89 continue 90 } 91 m.a = true 92 } 93 94 // populate the advrts that are current advertised 95 for _, path := range params.currentAdvertisements { 96 var ( 97 m *member 98 ok bool 99 ) 100 key := path.NLRI.String() 101 if m, ok = aset[key]; !ok { 102 aset[key] = &member{ 103 b: true, 104 advrt: path, 105 } 106 continue 107 } 108 m.b = true 109 } 110 111 for _, m := range aset { 112 // present in configured cidrs (set a) but not in advertised cidrs 113 // (set b) 114 if m.a && !m.b { 115 toAdvertise = append(toAdvertise, m.advrt) 116 } 117 // present in advertised cidrs (set b) but no in configured cidrs 118 // (set b) 119 if m.b && !m.a { 120 toWithdraw = append(toWithdraw, m.advrt) 121 } 122 // present in both configured (set a) and advertised (set b) add this to 123 // cidrs to leave advertised. 124 if m.b && m.a { 125 toKeep = append(toKeep, m.advrt) 126 } 127 } 128 129 if len(toAdvertise) == 0 && len(toWithdraw) == 0 { 130 l.Debugf("No reconciliation necessary") 131 return append([]*types.Path{}, params.currentAdvertisements...), nil 132 } 133 134 // create new adverts 135 for _, advrt := range toAdvertise { 136 l.Debugf("Advertising %s %v for policy with local ASN: %v", params.name, advrt.NLRI, params.newc.LocalASN) 137 advrtResp, err := params.sc.Server.AdvertisePath(params.ctx, types.PathRequest{Path: advrt}) 138 if err != nil { 139 return nil, fmt.Errorf("failed to advertise %s prefix %v: %w", params.name, advrt.NLRI, err) 140 } 141 newAdverts = append(newAdverts, advrtResp.Path) 142 } 143 144 // withdraw uneeded adverts 145 for _, advrt := range toWithdraw { 146 l.Debugf("Withdrawing %s %v for policy with local ASN: %v", params.name, advrt.NLRI, params.newc.LocalASN) 147 if err := params.sc.Server.WithdrawPath(params.ctx, types.PathRequest{Path: advrt}); err != nil { 148 return nil, err 149 } 150 } 151 152 // concat our toKeep and newAdverts slices to store the latest 153 // reconciliation and return it 154 return append(toKeep, newAdverts...), nil 155 }