Skip to content

Commit

Permalink
Add IPv4 tests
Browse files Browse the repository at this point in the history
Add IP address family validator
  • Loading branch information
damyan committed Sep 17, 2024
1 parent a9de1ce commit 86b1836
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 16 deletions.
19 changes: 13 additions & 6 deletions plugins/metal/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func handler6(req, resp dhcpv6.DHCPv6) (dhcpv6.DHCPv6, bool) {
return nil, true
}

if err := applyEndpointForMACAddress(mac); err != nil {
if err := applyEndpointForMACAddress(mac, ipamv1alpha1.CIPv6SubnetType); err != nil {
log.Errorf("Could not apply endpoint for mac %s: %s", mac.String(), err)
return resp, false
}
Expand All @@ -110,7 +110,7 @@ func handler4(req, resp *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, bool) {

mac := req.ClientHWAddr

if err := applyEndpointForMACAddress(mac); err != nil {
if err := applyEndpointForMACAddress(mac, ipamv1alpha1.CIPv4SubnetType); err != nil {
log.Errorf("Could not apply peer address: %s", err)
return resp, false
}
Expand All @@ -119,14 +119,14 @@ func handler4(req, resp *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, bool) {
return resp, false
}

func applyEndpointForMACAddress(mac net.HardwareAddr) error {
func applyEndpointForMACAddress(mac net.HardwareAddr, subnetFamily ipamv1alpha1.SubnetAddressType) error {
machineName, ok := machineMap[mac.String()]
if !ok {
// done here, next plugin
return fmt.Errorf("unknown machine MAC address: %s", mac.String())
}

ip, err := GetIPForMACAddress(mac)
ip, err := GetIPForMACAddress(mac, subnetFamily)
if err != nil {
return fmt.Errorf("could not get IP for MAC address %s: %s", mac.String(), err)
}
Expand Down Expand Up @@ -173,7 +173,7 @@ func ApplyEndpointForMachine(name string, mac net.HardwareAddr, ip *netip.Addr)
return nil
}

func GetIPForMACAddress(mac net.HardwareAddr) (*netip.Addr, error) {
func GetIPForMACAddress(mac net.HardwareAddr, subnetFamily ipamv1alpha1.SubnetAddressType) (*netip.Addr, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Expand All @@ -189,10 +189,17 @@ func GetIPForMACAddress(mac net.HardwareAddr) (*netip.Addr, error) {

sanitizedMAC := strings.Replace(mac.String(), ":", "", -1)
for _, ip := range ips.Items {
if ip.Labels["mac"] == sanitizedMAC {
if ip.Labels["mac"] == sanitizedMAC && ipFamilyMatches(ip, subnetFamily) {
return &ip.Status.Reserved.Net, nil
}
}

return nil, nil
}

func ipFamilyMatches(ip ipamv1alpha1.IP, subnetFamily ipamv1alpha1.SubnetAddressType) bool {
ipAddr := ip.Status.Reserved.String()

return strings.Contains(ipAddr, ":") && subnetFamily == "IPv6" ||
strings.Contains(ipAddr, ".") && subnetFamily == "IPv4"
}
112 changes: 102 additions & 10 deletions plugins/metal/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package metal
import (
"encoding/json"
"fmt"
"github.com/insomniacslk/dhcp/dhcpv4"
"github.com/insomniacslk/dhcp/dhcpv6"
ipamv1alpha1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1"
metalv1alpha1 "github.com/ironcore-dev/metal-operator/api/v1alpha1"
Expand All @@ -23,7 +24,7 @@ var _ = Describe("Endpoint", func() {
ns := SetupTest()

BeforeEach(func(ctx SpecContext) {
By("Creating an IPAM IP object")
By("Creating an IPAM IP objects")
mac := machineWithIPAddressMACAddress
m, err := net.ParseMAC(mac)
Expect(err).NotTo(HaveOccurred())
Expand All @@ -32,9 +33,9 @@ var _ = Describe("Endpoint", func() {
Expect(err).NotTo(HaveOccurred())

sanitizedMAC := strings.Replace(mac, ":", "", -1)
ipaddr, err := ipamv1alpha1.IPAddrFromString(linkLocalIPV6Addr.String())
ipv6Addr, err := ipamv1alpha1.IPAddrFromString(linkLocalIPV6Addr.String())
Expect(err).NotTo(HaveOccurred())
ip := &ipamv1alpha1.IP{
ipv6 := &ipamv1alpha1.IP{
ObjectMeta: metav1.ObjectMeta{
Namespace: ns.Name,
GenerateName: "test-",
Expand All @@ -46,14 +47,39 @@ var _ = Describe("Endpoint", func() {
Subnet: corev1.LocalObjectReference{
Name: "foo",
},
IP: ipaddr,
IP: ipv6Addr,
},
}
Expect(k8sClient.Create(ctx, ip)).To(Succeed())
DeferCleanup(k8sClient.Delete, ip)
Expect(k8sClient.Create(ctx, ipv6)).To(Succeed())
DeferCleanup(k8sClient.Delete, ipv6)

Eventually(UpdateStatus(ip, func() {
ip.Status.Reserved = ipaddr
Eventually(UpdateStatus(ipv6, func() {
ipv6.Status.Reserved = ipv6Addr
})).Should(Succeed())

ipv4Addr, err := ipamv1alpha1.IPAddrFromString(privateIPV4Address)
Expect(err).NotTo(HaveOccurred())
ipv4 := &ipamv1alpha1.IP{
ObjectMeta: metav1.ObjectMeta{
Namespace: ns.Name,
GenerateName: "test-",
Labels: map[string]string{
"mac": sanitizedMAC,
},
},
Spec: ipamv1alpha1.IPSpec{
Subnet: corev1.LocalObjectReference{
Name: "bar",
},
IP: ipv4Addr,
},
}

Expect(k8sClient.Create(ctx, ipv4)).To(Succeed())
DeferCleanup(k8sClient.Delete, ipv4)

Eventually(UpdateStatus(ipv4, func() {
ipv4.Status.Reserved = ipv4Addr
})).Should(Succeed())
})

Expand Down Expand Up @@ -138,7 +164,7 @@ var _ = Describe("Endpoint", func() {
It("Should not return an IP address for a known machine without IP address", func(ctx SpecContext) {
mac, _ := net.ParseMAC(machineWithoutIPAddressMACAddress)

ip, err := GetIPForMACAddress(mac)
ip, err := GetIPForMACAddress(mac, ipamv1alpha1.CIPv6SubnetType)
Eventually(err).Should(BeNil())
Eventually(ip).Should(BeNil())
})
Expand Down Expand Up @@ -184,7 +210,7 @@ var _ = Describe("Endpoint", func() {
_, _ = handler6(relayedRequest, stub)

epName := types.NamespacedName{
Name: "foo",
Name: machineWithIPAddressName,
}
endpoint := &metalv1alpha1.Endpoint{}

Expand All @@ -208,4 +234,70 @@ var _ = Describe("Endpoint", func() {
Eventually(resp).Should(BeNil())
Eventually(breakChain).Should(BeTrue())
})

/* IPv4 */
It("Should create an endpoint for IPv4 DHCP request from a known machine with IP address", func(ctx SpecContext) {
mac, _ := net.ParseMAC(machineWithIPAddressMACAddress)

req, _ := dhcpv4.NewDiscovery(mac)
stub, _ := dhcpv4.NewReplyFromRequest(req)

_, _ = handler4(req, stub)

endpoint := &metalv1alpha1.Endpoint{
ObjectMeta: metav1.ObjectMeta{
Name: machineWithIPAddressName,
},
}

Eventually(Object(endpoint)).Should(SatisfyAll(
HaveField("Spec.MACAddress", machineWithIPAddressMACAddress),
HaveField("Spec.IP", metalv1alpha1.MustParseIP(privateIPV4Address))))

DeferCleanup(k8sClient.Delete, endpoint)
})

It("Should not create an endpoint for IPv4 DHCP request from a known machine without IP address", func(ctx SpecContext) {
mac, _ := net.ParseMAC(machineWithoutIPAddressMACAddress)

req, _ := dhcpv4.NewDiscovery(mac)
stub, _ := dhcpv4.NewReplyFromRequest(req)

_, _ = handler4(req, stub)

epName := types.NamespacedName{
Name: machineWithoutIPAddressName,
}
endpoint := &metalv1alpha1.Endpoint{}

Eventually(func() error {
return k8sClient.Get(ctx, epName, endpoint)
}).ShouldNot(Succeed())
Eventually(func() bool {
err := k8sClient.Get(ctx, epName, endpoint)
return apierrors.IsNotFound(err)
}).Should(BeTrue())
})

It("Should not create an endpoint for IPv6 DHCP request from a unknown machine", func(ctx SpecContext) {
mac, _ := net.ParseMAC(unknownMachineMACAddress)

req, _ := dhcpv4.NewDiscovery(mac)
stub, _ := dhcpv4.NewReplyFromRequest(req)

_, _ = handler4(req, stub)

epName := types.NamespacedName{
Name: machineWithIPAddressName,
}
endpoint := &metalv1alpha1.Endpoint{}

Eventually(func() error {
return k8sClient.Get(ctx, epName, endpoint)
}).ShouldNot(Succeed())
Eventually(func() bool {
err := k8sClient.Get(ctx, epName, endpoint)
return apierrors.IsNotFound(err)
}).Should(BeTrue())
})
})
1 change: 1 addition & 0 deletions plugins/metal/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const (
machineWithoutIPAddressMACAddress = "47:11:47:11:47:11"
unknownMachineMACAddress = "11:11:11:11:11:11"
linkLocalIPV6Prefix = "fe80::"
privateIPV4Address = "192.168.47.11"
)

var (
Expand Down

0 comments on commit 86b1836

Please sign in to comment.