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