-
Notifications
You must be signed in to change notification settings - Fork 338
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
kubevirt, dhcp: Add DHCP with ARP Proxy to LSP
The hypershift workers use DHCP for IP configuration, this change configure the ipv4/ipv6 DHCP options from the VM's LSP with the cidr from switch subnet, harcode arp proxy IP as default gw and the dns server from kubernetes or openshift service, it also configure the "arp_proxy" option at the LSP. Signed-off-by: Enrique Llorente <[email protected]>
- Loading branch information
Showing
9 changed files
with
325 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package kubevirt | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net" | ||
|
||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
clientset "k8s.io/client-go/kubernetes" | ||
utilnet "k8s.io/utils/net" | ||
|
||
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/nbdb" | ||
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util" | ||
) | ||
|
||
const ( | ||
dhcpLeaseTime = 3500 | ||
) | ||
|
||
func ComposeDHCPOptions(k8scli clientset.Interface, hostname string, cidrs []*net.IPNet) (*nbdb.DHCPOptions, *nbdb.DHCPOptions, error) { | ||
if len(cidrs) == 0 { | ||
return nil, nil, fmt.Errorf("missing cidrs to compose dchp options") | ||
} | ||
if hostname == "" { | ||
return nil, nil, fmt.Errorf("missing hostname to compose dchp options") | ||
} | ||
dnsServer, err := k8scli.CoreV1().Services("kube-system").Get(context.Background(), "kube-dns", metav1.GetOptions{}) | ||
if err != nil { | ||
if !apierrors.IsNotFound(err) { | ||
return nil, nil, err | ||
} | ||
dnsServer, err = k8scli.CoreV1().Services("openshift-dns").Get(context.Background(), "dns-default", metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
} | ||
|
||
dnsServerIPv4, dnsServerIPv6 := sortServiceClusterIPs(dnsServer) | ||
var dhcpv4Options, dhcpv6Options *nbdb.DHCPOptions | ||
for _, cidr := range cidrs { | ||
if utilnet.IsIPv4CIDR(cidr) { | ||
dhcpv4Options = composeDHCPOptions(cidr.String(), ARPProxyIPv4, dnsServerIPv4, hostname) | ||
} else if utilnet.IsIPv6CIDR(cidr) { | ||
dhcpv6Options = composeDHCPOptions(cidr.String(), ARPProxyIPv6, dnsServerIPv6, hostname) | ||
} | ||
} | ||
return dhcpv4Options, dhcpv6Options, nil | ||
} | ||
|
||
func sortServiceClusterIPs(svc *corev1.Service) (string, string) { | ||
clusterIPv4 := "" | ||
clusterIPv6 := "" | ||
for _, clusterIP := range svc.Spec.ClusterIPs { | ||
if utilnet.IsIPv4String(clusterIP) { | ||
clusterIPv4 = clusterIP | ||
} else if utilnet.IsIPv6String(clusterIP) { | ||
clusterIPv6 = clusterIP | ||
} | ||
} | ||
return clusterIPv4, clusterIPv6 | ||
} | ||
|
||
func composeDHCPOptions(cidr string, arpProxyIP, dnsServer, hostname string) *nbdb.DHCPOptions { | ||
serverMAC := util.IPAddrToHWAddr(net.ParseIP(arpProxyIP)).String() | ||
return &nbdb.DHCPOptions{ | ||
Cidr: cidr, | ||
Options: map[string]string{ | ||
"lease_time": fmt.Sprintf("%d", dhcpLeaseTime), | ||
"router": arpProxyIP, | ||
"dns_server": dnsServer, | ||
"server_id": arpProxyIP, | ||
"server_mac": serverMAC, | ||
"hostname": fmt.Sprintf("%q", hostname), | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package kubevirt | ||
|
||
import ( | ||
"net" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/ginkgo/extensions/table" | ||
. "github.com/onsi/gomega" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/kubernetes/fake" | ||
|
||
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/nbdb" | ||
) | ||
|
||
var _ = Describe("Kubevirt", func() { | ||
type dhcpTest struct { | ||
cidrs []string | ||
hostname string | ||
dns *corev1.Service | ||
hasError bool | ||
expectedIPv4Options *nbdb.DHCPOptions | ||
expectedIPv6Options *nbdb.DHCPOptions | ||
} | ||
var ( | ||
svc = func(namespace string, name string, clusterIPs []string) *corev1.Service { | ||
return &corev1.Service{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Namespace: "kube-system", | ||
Name: "kube-dns", | ||
}, | ||
Spec: corev1.ServiceSpec{ | ||
ClusterIPs: clusterIPs, | ||
}, | ||
} | ||
} | ||
parseCIDR = func(cidr string) *net.IPNet { | ||
_, parsedCIDR, err := net.ParseCIDR(cidr) | ||
Expect(err).ToNot(HaveOccurred()) | ||
return parsedCIDR | ||
} | ||
) | ||
DescribeTable("composing dhcp options", func(t dhcpTest) { | ||
svcs := []corev1.Service{} | ||
if t.dns != nil { | ||
svcs = append(svcs, *t.dns) | ||
} | ||
fakeClient := fake.NewSimpleClientset(&corev1.ServiceList{ | ||
Items: svcs, | ||
}) | ||
cidrs := []*net.IPNet{} | ||
for _, cidr := range t.cidrs { | ||
cidrs = append(cidrs, parseCIDR(cidr)) | ||
} | ||
ipv4Options, ipv6Options, err := ComposeDHCPOptions(fakeClient, t.hostname, cidrs) | ||
if t.hasError { | ||
Expect(err).To(HaveOccurred()) | ||
} else { | ||
Expect(err).ToNot(HaveOccurred()) | ||
} | ||
Expect(ipv4Options).To(Equal(t.expectedIPv4Options)) | ||
Expect(ipv6Options).To(Equal(t.expectedIPv6Options)) | ||
}, | ||
Entry("IPv4 Single stack and k8s dns", dhcpTest{ | ||
cidrs: []string{"192.168.25.0/24"}, | ||
hostname: "foo1", | ||
dns: svc("kube-system", "core-dns", []string{"192.167.23.44"}), | ||
expectedIPv4Options: composeDHCPOptions("192.168.25.0/24", ARPProxyIPv4, "192.167.23.44", "foo1"), | ||
}), | ||
Entry("IPv6 Single stack and k8s dns", dhcpTest{ | ||
cidrs: []string{"2002:0:0:1234::/64"}, | ||
hostname: "foo1", | ||
dns: svc("kube-system", "core-dns", []string{"2001:1:2:3:4:5:6:7"}), | ||
expectedIPv6Options: composeDHCPOptions("2002:0:0:1234::/64", ARPProxyIPv6, "2001:1:2:3:4:5:6:7", "foo1"), | ||
}), | ||
Entry("Dual stack and k8s dns", dhcpTest{ | ||
cidrs: []string{"192.168.25.0/24", "2002:0:0:1234::/64"}, | ||
hostname: "foo1", | ||
dns: svc("kube-system", "core-dns", []string{"192.167.23.44", "2001:1:2:3:4:5:6:7"}), | ||
expectedIPv4Options: composeDHCPOptions("192.168.25.0/24", ARPProxyIPv4, "192.167.23.44", "foo1"), | ||
expectedIPv6Options: composeDHCPOptions("2002:0:0:1234::/64", ARPProxyIPv6, "2001:1:2:3:4:5:6:7", "foo1"), | ||
}), | ||
Entry("IPv4 Single stack and openshift dns", dhcpTest{ | ||
cidrs: []string{"192.168.25.0/24"}, | ||
hostname: "foo1", | ||
dns: svc("openshift-dns", "dns-default", []string{"192.167.23.44"}), | ||
expectedIPv4Options: composeDHCPOptions("192.168.25.0/24", ARPProxyIPv4, "192.167.23.44", "foo1"), | ||
}), | ||
Entry("IPv6 Single stack and openshift dns", dhcpTest{ | ||
cidrs: []string{"2002:0:0:1234::/64"}, | ||
hostname: "foo1", | ||
dns: svc("openshift-dns", "dns-default", []string{"2001:1:2:3:4:5:6:7"}), | ||
expectedIPv6Options: composeDHCPOptions("2002:0:0:1234::/64", ARPProxyIPv6, "2001:1:2:3:4:5:6:7", "foo1"), | ||
}), | ||
Entry("Dual stack and k8s openshift ", dhcpTest{ | ||
cidrs: []string{"192.168.25.0/24", "2002:0:0:1234::/64"}, | ||
hostname: "foo1", | ||
dns: svc("openshift-dns", "dns-default", []string{"192.167.23.44", "2001:1:2:3:4:5:6:7"}), | ||
expectedIPv4Options: composeDHCPOptions("192.168.25.0/24", ARPProxyIPv4, "192.167.23.44", "foo1"), | ||
expectedIPv6Options: composeDHCPOptions("2002:0:0:1234::/64", ARPProxyIPv6, "2001:1:2:3:4:5:6:7", "foo1"), | ||
}), | ||
Entry("No cidr should fail", dhcpTest{hasError: true}), | ||
Entry("No dns should fail", dhcpTest{cidrs: []string{"192.168.3.0/24"}, hasError: true}), | ||
Entry("No hostname should fail", dhcpTest{ | ||
hostname: "", | ||
cidrs: []string{"192.168.25.0/24"}, | ||
dns: svc("kube-system", "core-dns", []string{"192.167.23.44"}), | ||
hasError: true, | ||
}), | ||
) | ||
|
||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package kubevirt | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/onsi/ginkgo" | ||
"github.com/onsi/gomega" | ||
) | ||
|
||
func TestClusterNode(t *testing.T) { | ||
gomega.RegisterFailHandler(ginkgo.Fail) | ||
ginkgo.RunSpecs(t, "Kubevirt Suite") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package kubevirt | ||
|
||
import ( | ||
"net" | ||
"strings" | ||
|
||
"github.com/ovn-org/ovn-kubernetes/go-controller/pkg/util" | ||
) | ||
|
||
const ( | ||
ARPProxyIPv4 = "169.254.1.1" | ||
ARPProxyIPv6 = "d7b:6b4d:7b25:d22f::1" | ||
) | ||
|
||
func ARPProxyLSPOption() string { | ||
mac := util.IPAddrToHWAddr(net.ParseIP(ARPProxyIPv4)).String() | ||
return strings.Join([]string{mac, ARPProxyIPv4, ARPProxyIPv6}, " ") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters