Newer
Older
package controller
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"strings"
"time"
l2smv1 "github.com/Networks-it-uc3m/L2S-M/api/v1"
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
nettypes "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
NET_ATTACH_LABEL_PREFIX = "used-"
L2SM_NETWORK_ANNOTATION = "l2sm/networks"
MULTUS_ANNOTATION_KEY = "k8s.v1.cni.cncf.io/networks"
)
type NetworkAnnotation struct {
Name string `json:"name"`
Namespace string `json:"namespace,omitempty"`
IPAdresses []string `json:"ips,omitempty"`
}
func extractNetworks(annotations, namespace string) ([]NetworkAnnotation, error) {
var networks []NetworkAnnotation
err := json.Unmarshal([]byte(annotations), &networks)
if err != nil {
// If unmarshalling fails, treat as comma-separated list
names := strings.Split(annotations, ",")
for _, name := range names {
name = strings.TrimSpace(name)
if name != "" {
networks = append(networks, NetworkAnnotation{Name: name})
}
}
}
// Iterate over the networks to check if any IPAddresses are missing
for i := range networks {
if len(networks[i].IPAdresses) == 0 {
// Call GenerateIPv6Address if IPAddresses are missing
networks[i].GenerateIPv6Address()
}
networks[i].Namespace = namespace
}
return networks, nil
}
func GetL2Networks(ctx context.Context, c client.Client, networks []NetworkAnnotation) ([]l2smv1.L2Network, error) {
// List all L2Networks
l2Networks := &l2smv1.L2NetworkList{}
if err := c.List(ctx, l2Networks); err != nil {
return []l2smv1.L2Network{}, err
}
// Create a map of existing L2Network names to L2Network objects for quick lookup
existingNetworks := make(map[string]l2smv1.L2Network)
for _, network := range l2Networks.Items {
existingNetworks[network.Name] = network
}
// Collect the L2Networks that match the requested networks
var result l2smv1.L2NetworkList
for _, net := range networks {
if l2net, exists := existingNetworks[net.Name]; exists {
result.Items = append(result.Items, l2net)
} else {
return result.Items, fmt.Errorf("network %s doesn't exist", net.Name)
}
}
return result.Items, nil
}
func GetFreeNetAttachDefs(ctx context.Context, c client.Client, switchesNamespace, label string) nettypes.NetworkAttachmentDefinitionList {
// We define the network attachment definition list that will be later filled.
freeNetAttachDef := &nettypes.NetworkAttachmentDefinitionList{}
// We specify which net-attach-def we want. We want the ones that are specific to l2sm, in the overlay namespace and available in the desired node.
nodeSelector := labels.NewSelector()
nodeRequirement, _ := labels.NewRequirement(label, selection.NotIn, []string{"true"})
l2smRequirement, _ := labels.NewRequirement("app", selection.Equals, []string{"l2sm"})
nodeSelector.Add(*nodeRequirement)
nodeSelector.Add(*l2smRequirement)
listOptions := client.ListOptions{LabelSelector: nodeSelector, Namespace: switchesNamespace}
// We get the net-attach-def with the corresponding list options
c.List(ctx, freeNetAttachDef, &listOptions)
return *freeNetAttachDef
}
func (network *NetworkAnnotation) GenerateIPv6Address() {
rand.Seed(time.Now().UnixNano())
// Generating the interface ID (64 bits)
interfaceID := rand.Uint64()
// Formatting to a 16 character hexadecimal string
interfaceIDHex := fmt.Sprintf("%016x", interfaceID)
// Constructing the full IPv6 address in the fe80::/64 range
ipv6Address := fmt.Sprintf("fe80::%s:%s:%s:%s/64",
interfaceIDHex[:4], interfaceIDHex[4:8], interfaceIDHex[8:12], interfaceIDHex[12:])
network.IPAdresses = append(network.IPAdresses, ipv6Address)
}
func multusAnnotationToString(multusAnnotations []NetworkAnnotation) string {
jsonData, err := json.Marshal(multusAnnotations)
if err != nil {
return ""
}
return string(jsonData)
}
func (r *PodReconciler) DetachNetAttachDef(ctx context.Context, multusNetAttachDef NetworkAnnotation, namespace string) error {
netAttachDef := &nettypes.NetworkAttachmentDefinition{}
err := r.Get(ctx, client.ObjectKey{
Name: multusNetAttachDef.Name,
Namespace: namespace,
}, netAttachDef)
if err != nil {
return err
}
err = r.Delete(ctx, netAttachDef)
return err
}