-
Notifications
You must be signed in to change notification settings - Fork 2
/
plugin.go
105 lines (82 loc) · 2.45 KB
/
plugin.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
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors
// SPDX-License-Identifier: MIT
package ipam
import (
"fmt"
"github.com/coredhcp/coredhcp/handler"
"github.com/coredhcp/coredhcp/logger"
"github.com/coredhcp/coredhcp/plugins"
"net"
"os"
"github.com/insomniacslk/dhcp/dhcpv6"
"github.com/ironcore-dev/fedhcp/internal/api"
"gopkg.in/yaml.v3"
"github.com/mdlayher/netx/eui64"
)
var log = logger.GetLogger("plugins/ipam")
var Plugin = plugins.Plugin{
Name: "ipam",
Setup6: setup6,
}
var (
k8sClient *K8sClient
)
// args[0] = path to config file
func parseArgs(args ...string) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("exactly one argument must be passed to the metal plugin, got %d", len(args))
}
return args[0], nil
}
func loadConfig(args ...string) (*api.IPAMConfig, error) {
path, err := parseArgs(args...)
if err != nil {
return nil, fmt.Errorf("invalid configuration: %v", err)
}
log.Debugf("Reading ipam config file %s", path)
configData, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %v", err)
}
config := &api.IPAMConfig{}
if err = yaml.Unmarshal(configData, config); err != nil {
return nil, fmt.Errorf("failed to parse config file: %v", err)
}
return config, nil
}
func setup6(args ...string) (handler.Handler6, error) {
ipamConfig, err := loadConfig(args...)
if err != nil {
return nil, err
}
k8sClient, err = NewK8sClient(ipamConfig.Namespace, ipamConfig.Subnets)
if err != nil {
return nil, fmt.Errorf("failed to create k8s client: %w", err)
}
log.Printf("Loaded ipam plugin for DHCPv6.")
return handler6, nil
}
func handler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
log.Debugf("received DHCPv6 packet: %s", req.Summary())
if !req.IsRelay() {
log.Printf("Received non-relay DHCPv6 request. Dropping.")
return nil, true
}
relayMsg := req.(*dhcpv6.RelayMessage)
// Retrieve IPv6 prefix and MAC address from IPv6 address
_, mac, err := eui64.ParseIP(relayMsg.PeerAddr)
if err != nil {
log.Errorf("Could not parse peer address: %s", err)
return nil, true
}
ipaddr := make(net.IP, len(relayMsg.LinkAddr))
copy(ipaddr, relayMsg.LinkAddr)
ipaddr[len(ipaddr)-1] += 1
log.Infof("Generated IP address %s for mac %s", ipaddr.String(), mac.String())
err = k8sClient.createIpamIP(ipaddr, mac)
if err != nil {
log.Errorf("Could not create IPAM IP: %s", err)
return nil, true
}
return resp, false
}