Skip to content

Commit

Permalink
Change dhcp plugin to send ClientID allowing container to have multip…
Browse files Browse the repository at this point in the history
…le CNI

interfaces using dhcp ipam.

Vendor latest dhcp4server, dhcp4client, dhcp4

Added additional tests for new functionality in dhcp2_test.go

Wrap d2g dhcp4client calls with our own which add clientID to packet.
  • Loading branch information
mccv1r0 committed Nov 15, 2018
1 parent 227a4c1 commit 0af31fc
Show file tree
Hide file tree
Showing 17 changed files with 882 additions and 131 deletions.
121 changes: 121 additions & 0 deletions plugins/ipam/dhcp/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package main

import (
"github.com/d2g/dhcp4"
"github.com/d2g/dhcp4client"
)

const (
MaxDHCPLen = 576
)

//Send the Discovery Packet to the Broadcast Channel
func DhcpSendDiscoverPacket(c *dhcp4client.Client, options dhcp4.Options) (dhcp4.Packet, error) {
discoveryPacket := c.DiscoverPacket()

for opt, data := range options {
discoveryPacket.AddOption(opt, data)
}

discoveryPacket.PadToMinSize()
return discoveryPacket, c.SendPacket(discoveryPacket)
}

//Send Request Based On the offer Received.
func DhcpSendRequest(c *dhcp4client.Client, options dhcp4.Options, offerPacket *dhcp4.Packet) (dhcp4.Packet, error) {
requestPacket := c.RequestPacket(offerPacket)

for opt, data := range options {
requestPacket.AddOption(opt, data)
}

requestPacket.PadToMinSize()

return requestPacket, c.SendPacket(requestPacket)
}

//Send Decline to the received acknowledgement.
func DhcpSendDecline(c *dhcp4client.Client, acknowledgementPacket *dhcp4.Packet, options dhcp4.Options) (dhcp4.Packet, error) {
declinePacket := c.DeclinePacket(acknowledgementPacket)

for opt, data := range options {
declinePacket.AddOption(opt, data)
}

declinePacket.PadToMinSize()

return declinePacket, c.SendPacket(declinePacket)
}

//Lets do a Full DHCP Request.
func DhcpRequest(c *dhcp4client.Client, options dhcp4.Options) (bool, dhcp4.Packet, error) {
discoveryPacket, err := DhcpSendDiscoverPacket(c, options)
if err != nil {
return false, discoveryPacket, err
}

offerPacket, err := c.GetOffer(&discoveryPacket)
if err != nil {
return false, offerPacket, err
}

requestPacket, err := DhcpSendRequest(c, options, &offerPacket)
if err != nil {
return false, requestPacket, err
}

acknowledgement, err := c.GetAcknowledgement(&requestPacket)
if err != nil {
return false, acknowledgement, err
}

acknowledgementOptions := acknowledgement.ParseOptions()
if dhcp4.MessageType(acknowledgementOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.ACK {
return false, acknowledgement, nil
}

return true, acknowledgement, nil
}

//Renew a lease backed on the Acknowledgement Packet.
//Returns Sucessfull, The AcknoledgementPacket, Any Errors
func DhcpRenew(c *dhcp4client.Client, acknowledgement dhcp4.Packet, options dhcp4.Options) (bool, dhcp4.Packet, error) {
renewRequest := c.RenewalRequestPacket(&acknowledgement)

for opt, data := range options {
renewRequest.AddOption(opt, data)
}

renewRequest.PadToMinSize()

err := c.SendPacket(renewRequest)
if err != nil {
return false, renewRequest, err
}

newAcknowledgement, err := c.GetAcknowledgement(&renewRequest)
if err != nil {
return false, newAcknowledgement, err
}

newAcknowledgementOptions := newAcknowledgement.ParseOptions()
if dhcp4.MessageType(newAcknowledgementOptions[dhcp4.OptionDHCPMessageType][0]) != dhcp4.ACK {
return false, newAcknowledgement, nil
}

return true, newAcknowledgement, nil
}

//Release a lease backed on the Acknowledgement Packet.
//Returns Any Errors
func DhcpRelease(c *dhcp4client.Client, acknowledgement dhcp4.Packet, options dhcp4.Options) error {
release := c.ReleasePacket(&acknowledgement)

for opt, data := range options {
release.AddOption(opt, data)
}

release.PadToMinSize()

return c.SendPacket(release)
}
5 changes: 1 addition & 4 deletions plugins/ipam/dhcp/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ func newDHCP() *DHCP {
}

func generateClientID(containerID string, netName string, ifName string) string {
clientID := containerID + "/" + netName + "/" + ifName

return clientID
return containerID + "/" + netName + "/" + ifName
}

// Allocate acquires an IP from a DHCP server for a specified container.
Expand Down Expand Up @@ -118,7 +116,6 @@ func (d *DHCP) getLease(clientID string) *DHCPLease {
return l
}

//func (d *DHCP) setLease(contID, netName string, ifName string, l *DHCPLease) {
func (d *DHCP) setLease(clientID string, l *DHCPLease) {
d.mux.Lock()
defer d.mux.Unlock()
Expand Down
183 changes: 183 additions & 0 deletions plugins/ipam/dhcp/dhcp2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright 2015-2018 CNI authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"fmt"
"net"
"os"
"os/exec"
"sync"
"time"

"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containernetworking/plugins/pkg/testutils"

"github.com/vishvananda/netlink"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("DHCP Multiple Lease Operations", func() {
var originalNS, targetNS ns.NetNS
var dhcpServerStopCh chan bool
var dhcpServerDone *sync.WaitGroup
var clientCmd *exec.Cmd
var socketPath string
var tmpDir string
var serverIP net.IPNet
var err error

BeforeEach(func() {
dhcpServerStopCh, serverIP, socketPath, originalNS, targetNS, err = dhcpSetupOriginalNS()
Expect(err).NotTo(HaveOccurred())

// Move the container side to the container's NS
err = targetNS.Do(func(_ ns.NetNS) error {
defer GinkgoRecover()

link, err := netlink.LinkByName(contVethName0)
Expect(err).NotTo(HaveOccurred())
err = netlink.LinkSetUp(link)
Expect(err).NotTo(HaveOccurred())

link1, err := netlink.LinkByName(contVethName1)
Expect(err).NotTo(HaveOccurred())
err = netlink.LinkSetUp(link1)
Expect(err).NotTo(HaveOccurred())
return nil
})

// Start the DHCP server
dhcpServerDone, err = dhcpServerStart(originalNS, net.IPv4(192, 168, 1, 5), serverIP.IP, 2, dhcpServerStopCh)
Expect(err).NotTo(HaveOccurred())

// Start the DHCP client daemon
dhcpPluginPath, err := exec.LookPath("dhcp")
Expect(err).NotTo(HaveOccurred())
clientCmd = exec.Command(dhcpPluginPath, "daemon", "-socketpath", socketPath)
err = clientCmd.Start()
Expect(err).NotTo(HaveOccurred())
Expect(clientCmd.Process).NotTo(BeNil())

// Wait up to 15 seconds for the client socket
Eventually(func() bool {
_, err := os.Stat(socketPath)
return err == nil
}, time.Second*15, time.Second/4).Should(BeTrue())
})

AfterEach(func() {
dhcpServerStopCh <- true
dhcpServerDone.Wait()
clientCmd.Process.Kill()
clientCmd.Wait()

Expect(originalNS.Close()).To(Succeed())
Expect(targetNS.Close()).To(Succeed())
defer os.RemoveAll(tmpDir)
})

It("configures multiple links with multiple ADD/DEL", func() {
conf := fmt.Sprintf(`{
"cniVersion": "0.3.1",
"name": "mynet",
"type": "bridge",
"bridge": "%s",
"ipam": {
"type": "dhcp",
"daemonSocketPath": "%s"
}
}`, hostBridgeName, socketPath)

args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNS.Path(),
IfName: contVethName0,
StdinData: []byte(conf),
}

var addResult *current.Result
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())

addResult, err = current.GetResult(r)
Expect(err).NotTo(HaveOccurred())
Expect(len(addResult.IPs)).To(Equal(1))
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.5/24"))
return nil
})
Expect(err).NotTo(HaveOccurred())

args = &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNS.Path(),
IfName: contVethName1,
StdinData: []byte(conf),
}

err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())

addResult, err = current.GetResult(r)
Expect(err).NotTo(HaveOccurred())
Expect(len(addResult.IPs)).To(Equal(1))
Expect(addResult.IPs[0].Address.String()).To(Equal("192.168.1.6/24"))
return nil
})
Expect(err).NotTo(HaveOccurred())

args = &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNS.Path(),
IfName: contVethName1,
StdinData: []byte(conf),
}

err = originalNS.Do(func(ns.NetNS) error {
return testutils.CmdDelWithArgs(args, func() error {
return cmdDel(args)
})
})
Expect(err).NotTo(HaveOccurred())

args = &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNS.Path(),
IfName: contVethName0,
StdinData: []byte(conf),
}

err = originalNS.Do(func(ns.NetNS) error {
return testutils.CmdDelWithArgs(args, func() error {
return cmdDel(args)
})
})
Expect(err).NotTo(HaveOccurred())
})
})
Loading

0 comments on commit 0af31fc

Please sign in to comment.