Skip to content

Commit 28a37d8

Browse files
authored
Merge pull request #140 from telekom/feature/cfg-hot-replace
Add FRR config hot-replace feature
2 parents 8e0d22f + 1f5aecc commit 28a37d8

File tree

4 files changed

+33
-10
lines changed

4 files changed

+33
-10
lines changed

pkg/config/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,21 @@ type Config struct {
1818
BPFInterfaces []string `yaml:"bpfInterfaces"`
1919
SkipVRFConfig []string `yaml:"skipVRFConfig"`
2020
ServerASN int `yaml:"serverASN"`
21+
22+
Replacements []Replacement `yaml:"replacements"`
2123
}
2224

2325
type VRFConfig struct {
2426
VNI int `yaml:"vni"`
2527
RT string `yaml:"rt"`
2628
}
2729

30+
type Replacement struct {
31+
Old string `yaml:"old"`
32+
New string `yaml:"new"`
33+
Regex bool `yaml:"regex"`
34+
}
35+
2836
func LoadConfig() (*Config, error) {
2937
config := &Config{}
3038

pkg/frr/configure.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"regexp"
88

9+
"github.com/telekom/das-schiff-network-operator/pkg/config"
910
"github.com/telekom/das-schiff-network-operator/pkg/healthcheck"
1011
"github.com/telekom/das-schiff-network-operator/pkg/nl"
1112
)
@@ -33,7 +34,7 @@ type templateConfig struct {
3334
HostRouterID string
3435
}
3536

36-
func (m *Manager) Configure(in Configuration, nm *nl.Manager) (bool, error) {
37+
func (m *Manager) Configure(in Configuration, nm *nl.Manager, nwopCfg *config.Config) (bool, error) {
3738
// Remove permit from VRF and only allow deny rules for mgmt VRFs
3839
for i := range in.VRFs {
3940
if in.VRFs[i].Name != m.mgmtVrf {
@@ -50,7 +51,7 @@ func (m *Manager) Configure(in Configuration, nm *nl.Manager) (bool, error) {
5051
}
5152
}
5253

53-
config, err := m.renderSubtemplates(in, nm)
54+
frrConfig, err := m.renderSubtemplates(in, nm)
5455
if err != nil {
5556
return false, err
5657
}
@@ -60,12 +61,13 @@ func (m *Manager) Configure(in Configuration, nm *nl.Manager) (bool, error) {
6061
return false, fmt.Errorf("error reading configuration file: %w", err)
6162
}
6263

63-
targetConfig, err := render(m.configTemplate, config)
64+
targetConfig, err := render(m.configTemplate, frrConfig)
6465
if err != nil {
6566
return false, err
6667
}
6768

6869
targetConfig = fixRouteTargetReload(targetConfig)
70+
targetConfig = applyCfgReplacements(targetConfig, nwopCfg.Replacements)
6971

7072
if !bytes.Equal(currentConfig, targetConfig) {
7173
err = os.WriteFile(m.ConfigPath, targetConfig, frrPermissions)
@@ -154,8 +156,8 @@ func (m *Manager) renderSubtemplates(in Configuration, nlManager *nl.Manager) (*
154156

155157
// fixRouteTargetReload is a workaround for FRR's inability to reload route-targets if they are configured in a single line.
156158
// This function splits such lines into multiple lines, each containing a single route-target.
157-
func fixRouteTargetReload(config []byte) []byte {
158-
return rtLinesRe.ReplaceAllFunc(config, func(s []byte) []byte {
159+
func fixRouteTargetReload(frrConfig []byte) []byte {
160+
return rtLinesRe.ReplaceAllFunc(frrConfig, func(s []byte) []byte {
159161
parts := rtPartsRe.FindSubmatch(s)
160162
if parts == nil {
161163
return s
@@ -172,3 +174,16 @@ func fixRouteTargetReload(config []byte) []byte {
172174
return []byte(lines[:len(lines)-1])
173175
})
174176
}
177+
178+
// applyCfgReplacements replaces placeholders in the configuration with the actual values.
179+
func applyCfgReplacements(frrConfig []byte, replacements []config.Replacement) []byte {
180+
for _, replacement := range replacements {
181+
if !replacement.Regex {
182+
frrConfig = bytes.ReplaceAll(frrConfig, []byte(replacement.Old), []byte(replacement.New))
183+
} else {
184+
re := regexp.MustCompile(replacement.Old)
185+
frrConfig = re.ReplaceAll(frrConfig, []byte(replacement.New))
186+
}
187+
}
188+
return frrConfig
189+
}

pkg/frr/frr_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ var _ = Describe("frr", func() {
134134
It("return error if cannot get underlay IP", func() {
135135
m := &Manager{}
136136
nlMock.EXPECT().AddrList(gomock.Any(), gomock.Any()).Return(nil, errors.New("error listing addresses"))
137-
_, err := m.Configure(Configuration{}, nl.NewManager(nlMock))
137+
_, err := m.Configure(Configuration{}, nl.NewManager(nlMock), &config.Config{})
138138
Expect(err).To(HaveOccurred())
139139
})
140140
It("return error if cannot node's name", func() {
@@ -148,7 +148,7 @@ var _ = Describe("frr", func() {
148148
nlMock.EXPECT().AddrList(gomock.Any(), gomock.Any()).Return([]netlink.Addr{
149149
{IPNet: netlink.NewIPNet(net.IPv4(0, 0, 0, 0))},
150150
}, nil)
151-
_, err := m.Configure(Configuration{}, nl.NewManager(nlMock))
151+
_, err := m.Configure(Configuration{}, nl.NewManager(nlMock), &config.Config{})
152152
Expect(err).To(HaveOccurred())
153153

154154
if isSet {
@@ -165,7 +165,7 @@ var _ = Describe("frr", func() {
165165
nlMock.EXPECT().AddrList(gomock.Any(), gomock.Any()).Return([]netlink.Addr{
166166
{IPNet: netlink.NewIPNet(net.IPv4(0, 0, 0, 0))},
167167
}, nil)
168-
_, err = m.Configure(Configuration{}, nl.NewManager(nlMock))
168+
_, err = m.Configure(Configuration{}, nl.NewManager(nlMock), &config.Config{})
169169
Expect(err).To(HaveOccurred())
170170

171171
if isSet {
@@ -189,7 +189,7 @@ var _ = Describe("frr", func() {
189189
nlMock.EXPECT().AddrList(gomock.Any(), gomock.Any()).Return([]netlink.Addr{
190190
{IPNet: netlink.NewIPNet(net.IPv4(0, 0, 0, 0))},
191191
}, nil)
192-
_, err = m.Configure(Configuration{}, nl.NewManager(nlMock))
192+
_, err = m.Configure(Configuration{}, nl.NewManager(nlMock), &config.Config{})
193193
Expect(err).To(HaveOccurred())
194194

195195
if isSet {

pkg/reconciler/layer3.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func (r *reconcile) configureFRR(vrfConfigs []frr.VRFConfiguration, reloadTwice
100100
changed, err := r.frrManager.Configure(frr.Configuration{
101101
VRFs: vrfConfigs,
102102
ASN: r.config.ServerASN,
103-
}, r.netlinkManager)
103+
}, r.netlinkManager, r.config)
104104
if err != nil {
105105
r.Logger.Error(err, "error updating FRR configuration")
106106
return fmt.Errorf("error updating FRR configuration: %w", err)

0 commit comments

Comments
 (0)