Skip to content

Commit

Permalink
Merge pull request projectcalico#1250 from robbrockbank/host-local-wg
Browse files Browse the repository at this point in the history
For host local IPAM use the first IP in the CIDR block for wireguard as well as IPIP
  • Loading branch information
Rob Brockbank authored Jun 8, 2020
2 parents 89d6679 + b325d82 commit 871c78f
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 18 deletions.
47 changes: 30 additions & 17 deletions lib/backend/k8s/resources/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,39 +233,52 @@ func K8sNodeToCalico(k8sNode *kapiv1.Node, usePodCIDR bool) (*model.KVPair, erro
bgpSpec.ASNumber = &asn
}
}
bgpSpec.IPv4IPIPTunnelAddr = annotations[nodeBgpIpv4IPIPTunnelAddrAnnotation]

// Initialize the wireguard spec. We'll include it if it contains non-zero data.
wireguardSpec := &apiv3.NodeWireguardSpec{}

// Add in an orchestrator reference back to the Kubernetes node name.
calicoNode.Spec.OrchRefs = []apiv3.OrchRef{{NodeName: k8sNode.Name, Orchestrator: apiv3.OrchestratorKubernetes}}

// If using host-local IPAM, assign an IPIP tunnel address statically.
// If using host-local IPAM, assign an IPIP and wireguard tunnel address statically. They can both have the same IP.
if usePodCIDR && k8sNode.Spec.PodCIDR != "" {
// For back compatibility with v2.6.x, always generate a tunnel address if we have the pod CIDR.
bgpSpec.IPv4IPIPTunnelAddr, err = getIPIPTunnelAddress(k8sNode)
// For back compatibility with v2.6.x, always generate an IPIP tunnel address if we have the pod CIDR.
tunnelAddr, err := getStaticTunnelAddress(k8sNode)
if err != nil {
return nil, err
}
bgpSpec.IPv4IPIPTunnelAddr = tunnelAddr

// Only assign the wireguard tunnel IP if we have a public key assigned - this is inline with how the IPs are
// assigned in the calico IPAM scenarios.
if annotations[nodeWireguardPublicKeyAnnotation] != "" {
wireguardSpec.InterfaceIPv4Address = tunnelAddr
}
} else {
// We are not using host local, so assign tunnel addresses from annotations.
bgpSpec.IPv4IPIPTunnelAddr = annotations[nodeBgpIpv4IPIPTunnelAddrAnnotation]
wireguardSpec.InterfaceIPv4Address = annotations[nodeWireguardIpv4IfaceAddrAnnotation]
}

// Only set the BGP spec if it is not empty.
if !reflect.DeepEqual(*bgpSpec, apiv3.NodeBGPSpec{}) {
calicoNode.Spec.BGP = bgpSpec
}

// Only set the Wireguard spec if it is not empty.
if !reflect.DeepEqual(*wireguardSpec, apiv3.NodeWireguardSpec{}) {
calicoNode.Spec.Wireguard = wireguardSpec
}

// Set the VXLAN tunnel address based on annotation.
calicoNode.Spec.IPv4VXLANTunnelAddr = annotations[nodeBgpIpv4VXLANTunnelAddrAnnotation]
calicoNode.Spec.VXLANTunnelMACAddr = annotations[nodeBgpVXLANTunnelMACAddrAnnotation]

// Set the Wireguard interface address and public-key based on annotation.
wireguardSpec := &apiv3.NodeWireguardSpec{}
wireguardSpec.InterfaceIPv4Address = annotations[nodeWireguardIpv4IfaceAddrAnnotation]
wireguardStatus := apiv3.NodeStatus{}
wireguardStatus.WireguardPublicKey = annotations[nodeWireguardPublicKeyAnnotation]
if !reflect.DeepEqual(*wireguardSpec, apiv3.NodeWireguardSpec{}) {
calicoNode.Spec.Wireguard = wireguardSpec
}
if !reflect.DeepEqual(wireguardStatus, apiv3.NodeStatus{}) {
calicoNode.Status = wireguardStatus
// Set the node status
nodeStatus := apiv3.NodeStatus{}
nodeStatus.WireguardPublicKey = annotations[nodeWireguardPublicKeyAnnotation]
if !reflect.DeepEqual(nodeStatus, apiv3.NodeStatus{}) {
calicoNode.Status = nodeStatus
}

// Fill in status with Kubernetes pod CIDRs.
Expand Down Expand Up @@ -457,9 +470,9 @@ func restoreCalicoLabels(calicoNode *apiv3.Node) (*apiv3.Node, error) {
return calicoNode, nil
}

// getIPIPTunnelAddress calculates the IPv4 address to use for the IPIP tunnel based on the node's pod CIDR, for use
// in conjunction with host-local IPAM backed by node.Spec.PodCIDR allocations.
func getIPIPTunnelAddress(n *kapiv1.Node) (string, error) {
// getStaticTunnelAddress calculates the IPv4 address to use for the IPIP tunnel and wireguard tunnel based on the
// node's pod CIDR, for use in conjunction with host-local IPAM backed by node.Spec.PodCIDR allocations.
func getStaticTunnelAddress(n *kapiv1.Node) (string, error) {
ip, _, err := net.ParseCIDR(n.Spec.PodCIDR)
if err != nil {
log.Warnf("Invalid pod CIDR for node: %s, %s", n.Name, n.Spec.PodCIDR)
Expand Down
37 changes: 36 additions & 1 deletion lib/backend/k8s/resources/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ var _ = Describe("Test Node conversion", func() {
})

Context("using host-local IPAM backed by pod CIDR", func() {
It("should parse a k8s Node to a Calico Node with an IPv4IPIPTunnelAddr", func() {
It("should parse a k8s Node to a Calico Node with an IPv4IPIPTunnelAddr and no wireguard tunnel addr if there is no public key", func() {
node := k8sapi.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "TestNode",
Expand All @@ -431,11 +431,46 @@ var _ = Describe("Test Node conversion", func() {
// Ensure we got the correct values.
bgpIpv4Address := n.Value.(*apiv3.Node).Spec.BGP.IPv4Address
ipInIpAddr := n.Value.(*apiv3.Node).Spec.BGP.IPv4IPIPTunnelAddr
wg := n.Value.(*apiv3.Node).Spec.Wireguard
asn := n.Value.(*apiv3.Node).Spec.BGP.ASNumber
ip := net.ParseIP("172.17.17.10")

Expect(bgpIpv4Address).To(Equal(ip.String()))
Expect(ipInIpAddr).To(Equal("10.0.0.1"))
Expect(wg).To(BeNil())
Expect(asn.String()).To(Equal("2546"))
})

It("should parse a k8s Node to a Calico Node with an IPv4IPIPTunnelAddr and a wireguard tunnel addr if there is a public key", func() {
node := k8sapi.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "TestNode",
ResourceVersion: "1234",
Annotations: map[string]string{
nodeBgpIpv4AddrAnnotation: "172.17.17.10",
nodeBgpAsnAnnotation: "2546",
nodeWireguardPublicKeyAnnotation: "abcd",
},
},
Spec: k8sapi.NodeSpec{
PodCIDR: "10.0.0.0/24",
},
}

n, err := K8sNodeToCalico(&node, true)
Expect(err).NotTo(HaveOccurred())

// Ensure we got the correct values.
bgpIpv4Address := n.Value.(*apiv3.Node).Spec.BGP.IPv4Address
ipInIpAddr := n.Value.(*apiv3.Node).Spec.BGP.IPv4IPIPTunnelAddr
wg := n.Value.(*apiv3.Node).Spec.Wireguard
asn := n.Value.(*apiv3.Node).Spec.BGP.ASNumber
ip := net.ParseIP("172.17.17.10")

Expect(bgpIpv4Address).To(Equal(ip.String()))
Expect(ipInIpAddr).To(Equal("10.0.0.1"))
Expect(wg).ToNot(BeNil())
Expect(wg.InterfaceIPv4Address).To(Equal("10.0.0.1"))
Expect(asn.String()).To(Equal("2546"))
})

Expand Down

0 comments on commit 871c78f

Please sign in to comment.