Skip to content

Commit 2b2a49d

Browse files
committed
Merge branch 'feature/http'
2 parents 8eec117 + bddbb3c commit 2b2a49d

File tree

5 files changed

+144
-7
lines changed

5 files changed

+144
-7
lines changed

config/config.yaml

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
# pre-exit-hook:
55
# post-exit-hook:
66

7+
http-address: "192.0.2.1"
8+
http-port: "8080"
9+
controller-uri: "http://192.0.2.2:8080"
10+
backbone-ip: "fd00::01"
11+
712
linux-headend-set-source-address: "fd00:51D5:0000::"
813
ipv4-headend-prefix: "10.0.200.3/32"
914
headends:
@@ -21,7 +26,7 @@ headends:
2126
- "fd00:51D5:0000:4::"
2227
source-address-prefix: "fd00:51D5:000:1:9999::/80"
2328
- name: "linux test"
24-
to: "10.0.300.0/24"
29+
to: "10.0.100.0/24"
2530
provider: "Linux"
2631
behavior: "H.Encaps"
2732
policy:

internal/app/setup.go

+29-3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ func (s *Setup) AddTasks() {
5555
// 0.2 post-hooks
5656
s.RegisterTask("hook.post", tasks.NewMultiHook(postInitHook, postExitHook))
5757

58+
httpPort := "80" // default http port
59+
if s.config.HTTPPort != nil {
60+
httpPort = *s.config.HTTPPort
61+
}
62+
httpURI := "http://" + s.config.HTTPAddress + httpPort
63+
// 0.3 http server
64+
// 0.4 controller registry
65+
if s.config.Locator != nil {
66+
s.RegisterTask("ctrl.registry", tasks.NewControllerRegistry(s.config.ControllerURI, s.config.BackboneIP, *s.config.Locator, httpURI))
67+
}
68+
5869
// 1. ifaces
5970
// 1.1 iface linux (type dummy)
6071
s.RegisterTask("iproute2.iface.linux", tasks.NewTaskDummyIface(constants.IFACE_LINUX))
@@ -149,11 +160,18 @@ func (s *Setup) RunExitTask(name string) error {
149160

150161
// Init
151162
func (s *Setup) Init() error {
152-
// 0. user pre-hook
163+
// 0.1. user pre-hook
153164
if err := s.RunInitTask("hook.pre"); err != nil {
154165
return err
155166
}
156167

168+
// 0.2. register into controller
169+
if s.config.Locator != nil {
170+
if err := s.RunInitTask("ctrl.registry"); err != nil {
171+
return err
172+
}
173+
}
174+
157175
// 1. ifaces
158176
// 1.1 iface linux (type dummy)
159177
if err := s.RunInitTask("iproute2.iface.linux"); err != nil {
@@ -247,10 +265,18 @@ func (s *Setup) Exit() {
247265
// and a maximum of exit tasks must be run,
248266
// even if previous one resulted in errors.
249267

250-
// 0. user pre-hook
268+
// 0.1. user pre-hook
251269
if err := s.RunExitTask("hook.pre"); err != nil {
252270
fmt.Println(err)
253271
}
272+
273+
// 0.2. unregister from controller
274+
if s.config.Locator != nil {
275+
if err := s.RunExitTask("ctrl.registry"); err != nil {
276+
fmt.Println(err)
277+
}
278+
}
279+
254280
// 1. ip rules
255281
// 1.1 rule to rttable nextmn-gtp4
256282
if s.config.GTP4HeadendPrefix != nil {
@@ -268,7 +294,7 @@ func (s *Setup) Exit() {
268294
// 2 endpoints + headends
269295
// 2. nextmn gtp4 headends
270296
for _, h := range s.config.Headends.FilterWithBehavior(config.ProviderNextMN, config.H_M_GTP4_D) {
271-
t_name := fmt.Sprintf("nextmn.headend/%s", h.Name)
297+
t_name := fmt.Sprintf("nextmn.headend.gtp4/%s", h.Name)
272298
if err := s.RunExitTask(t_name); err != nil {
273299
fmt.Println(err)
274300
}

internal/config/config.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package config
66

77
import (
88
"io/ioutil"
9+
"net/netip"
910
"path/filepath"
1011

1112
"gopkg.in/yaml.v3"
@@ -28,9 +29,19 @@ func ParseConf(file string) (*SRv6Config, error) {
2829
}
2930

3031
type SRv6Config struct {
31-
Debug *bool `yaml:debug,omitempty"`
32+
Debug *bool `yaml:"debug,omitempty"`
3233
Hooks *Hooks `yaml:"hooks"`
3334

35+
// interface with controller
36+
HTTPAddress string `yaml:"http-address"`
37+
HTTPPort *string `yaml:"http-port,omitempty"` // default: 80
38+
// TODO: use a better type for this information
39+
ControllerURI string `yaml:"controller-uri"` // example: http://192.0.2.2/8080
40+
41+
// Backbone IPv6 address
42+
// TODO: use a better type for this information
43+
BackboneIP netip.Addr `yaml:"backbone-ip"`
44+
3445
// headends
3546
LinuxHeadendSetSourceAddress *string `yaml:"linux-headend-set-source-address,omitempty"`
3647
GTP4HeadendPrefix *string `yaml:"ipv4-headend-prefix,omitempty"` // example of prefix: 10.0.0.1/32 (if you use a single IPv4 headend) or 10.0.1.0/24 (with more headends)

internal/tasks/controller-registry.go

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2023 Louis Royer and the NextMN-SRv6 contributors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style license that can be
3+
// found in the LICENSE file.
4+
// SPDX-License-Identifier: MIT
5+
package tasks
6+
7+
import (
8+
"bytes"
9+
"encoding/json"
10+
"fmt"
11+
"net/http"
12+
"net/netip"
13+
)
14+
15+
// ControllerRegistry registers and unregisters into controller
16+
type ControllerRegistry struct {
17+
WithState
18+
RemoteControlURI string // URI of the controller
19+
LocalControlURI string // URI of the router, used to control it
20+
Locator string
21+
Backbone netip.Addr
22+
Resource string
23+
}
24+
25+
// Create a new ControllerRegistry
26+
func NewControllerRegistry(remoteControlURI string, backbone netip.Addr, locator string, localControlURI string) *ControllerRegistry {
27+
return &ControllerRegistry{
28+
WithState: NewState(),
29+
RemoteControlURI: remoteControlURI,
30+
LocalControlURI: localControlURI,
31+
Locator: locator,
32+
Backbone: backbone,
33+
Resource: "",
34+
}
35+
}
36+
37+
// Init
38+
func (t *ControllerRegistry) RunInit() error {
39+
data := map[string]string{
40+
"locator": t.Locator,
41+
"backbone": t.Backbone.String(),
42+
"control": t.LocalControlURI,
43+
}
44+
json_data, err := json.Marshal(data)
45+
if err != nil {
46+
return err
47+
}
48+
// TODO: retry on timeout failure
49+
resp, err := http.Post(t.RemoteControlURI+"/routers", "application/json", bytes.NewBuffer(json_data))
50+
if err != nil {
51+
return err
52+
}
53+
defer resp.Body.Close()
54+
if resp.StatusCode == 400 {
55+
return fmt.Errorf("HTTP Bad request\n")
56+
}
57+
if resp.StatusCode >= 500 {
58+
return fmt.Errorf("HTTP Control Server: internal error\n")
59+
}
60+
if resp.StatusCode == 201 { // created
61+
t.Resource = resp.Header.Get("Location")
62+
}
63+
64+
t.state = true
65+
return nil
66+
}
67+
68+
// Exit
69+
func (t *ControllerRegistry) RunExit() error {
70+
// TODO: retry on timeout failure
71+
// TODO: if Resource has scheme, don't concatenate
72+
if t.Resource == "" {
73+
// nothing to do
74+
t.state = false
75+
return nil
76+
}
77+
req, err := http.NewRequest("DELETE", t.RemoteControlURI+t.Resource, nil)
78+
if err != nil {
79+
return err
80+
}
81+
client := &http.Client{}
82+
resp, err := client.Do(req)
83+
if err != nil {
84+
return err
85+
}
86+
defer resp.Body.Close()
87+
if resp.StatusCode == 400 {
88+
return fmt.Errorf("HTTP Bad request\n")
89+
}
90+
if resp.StatusCode >= 500 {
91+
return fmt.Errorf("HTTP Control Server: internal error %v\n", resp.Body)
92+
}
93+
t.state = false
94+
return nil
95+
}

main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ func main() {
6565
}(ch, setup)
6666
setup.AddTasks()
6767
if err := setup.Run(); err != nil {
68-
fmt.Println("Error while running, exiting…")
69-
log.Fatal(err)
68+
fmt.Println("Error while running, exiting…:", err)
69+
setup.Exit()
7070
os.Exit(2)
7171
}
7272
return nil

0 commit comments

Comments
 (0)