Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CNI v1.1 support #1021

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
module github.com/containernetworking/plugins

go 1.20
go 1.21

toolchain go1.22.1

require (
github.com/Microsoft/hcsshim v0.12.0
github.com/alexflint/go-filemutex v1.3.0
github.com/buger/jsonparser v1.1.1
github.com/containernetworking/cni v1.1.2
github.com/containernetworking/cni v1.2.0-rc1
github.com/coreos/go-iptables v0.7.0
github.com/coreos/go-systemd/v22 v22.5.0
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c
github.com/d2g/dhcp4client v1.0.0
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5
github.com/godbus/dbus/v5 v5.1.0
github.com/mattn/go-shellwords v1.0.12
github.com/networkplumbing/go-nft v0.4.0
github.com/onsi/ginkgo/v2 v2.16.0
github.com/onsi/gomega v1.31.1
github.com/opencontainers/selinux v1.11.0
github.com/safchain/ethtool v0.3.0
github.com/tidwall/gjson v1.17.1
github.com/tidwall/sjson v1.2.5
github.com/vishvananda/netlink v1.2.1-beta.2
golang.org/x/net v0.20.0
golang.org/x/sys v0.17.0
)

require (
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/containerd/cgroups/v3 v3.0.2 // indirect
github.com/containerd/errdefs v0.1.0 // indirect
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
Expand All @@ -37,10 +41,11 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/testify v1.8.2 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
Expand Down
63 changes: 14 additions & 49 deletions go.sum

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions pkg/ip/ipmasq_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,46 @@ func TeardownIPMasq(ipn *net.IPNet, chain string, comment string) error {
return nil
}

func CheckIPMasq(ipn *net.IPNet, chain, comment string) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing comments for the function?

isV6 := ipn.IP.To4() == nil

var ipt *iptables.IPTables
var err error
var multicastNet string
var ip string // the ip and its full-length prefix

if isV6 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isV6 seems to be used only here. So how about to replace it with ipn.IP.To4() == nil directly?

ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv6)
multicastNet = "ff00::/8"
ip = ipn.IP.String() + "/128"
} else {
ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv4)
multicastNet = "224.0.0.0/4"
ip = ipn.IP.String() + "/32"
}
if err != nil {
return fmt.Errorf("failed to locate iptables: %v", err)
}

ok, err := ipt.Exists("nat", chain, "!", "-d", multicastNet, "-j", "MASQUERADE", "-m", "comment", "--comment", comment)
if err != nil {
return fmt.Errorf("could not check for expected rule: %w", err)
}
if !ok {
return fmt.Errorf("expected rule did not exist in chain %s", chain)
}

ok, err = ipt.Exists("nat", "POSTROUTING", "-s", ip, "-j", chain, "-m", "comment", "--comment", comment)
if err != nil {
return fmt.Errorf("could not check for expected rule [-A POSTROUTING ]: %w", err)
}
if !ok {
want := []string{"-A", "POSTROUTING", "-s", ip, "-j", chain, "-m", "comment", "--comment", comment}
return fmt.Errorf("expected rule %v did not exist in chain POSTROUTING", want)
}
return nil
}

// isNotExist returnst true if the error is from iptables indicating
// that the target does not exist.
func isNotExist(err error) bool {
Expand Down
8 changes: 8 additions & 0 deletions pkg/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ func ExecCheck(plugin string, netconf []byte) error {
func ExecDel(plugin string, netconf []byte) error {
return invoke.DelegateDel(context.TODO(), plugin, netconf, nil)
}

func ExecStatus(plugin string, netconf []byte) error {
return invoke.DelegateStatus(context.TODO(), plugin, netconf, nil)
}

func ExecGC(plugin string, netconf []byte) error {
return invoke.DelegateGC(context.TODO(), plugin, netconf, nil)
}
9 changes: 9 additions & 0 deletions pkg/ipam/ipam_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ func ConfigureIface(ifName string, res *current.Result) error {
Dst: &r.Dst,
LinkIndex: link.Attrs().Index,
Gw: gw,
MTU: r.MTU,
AdvMSS: r.AdvMSS,
Priority: r.Priority,
}
if r.Scope != nil {
route.Scope = netlink.Scope(*r.Scope)
}
if r.Table != nil {
route.Table = *r.Table
}

if err = netlink.RouteAddEcmp(&route); err != nil {
Expand Down
18 changes: 18 additions & 0 deletions pkg/testutils/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,21 @@ func CmdDel(cniNetns, cniContainerID, cniIfname string, f func() error) error {
func CmdDelWithArgs(args *skel.CmdArgs, f func() error) error {
return CmdDel(args.Netns, args.ContainerID, args.IfName, f)
}

func CmdGC(f func() error) error {
os.Setenv("CNI_COMMAND", "GC")
os.Setenv("CNI_PATH", os.Getenv("PATH"))
os.Setenv("CNI_NETNS_OVERRIDE", "1")
defer envCleanup()

return f()
}

func CmdStatus(f func() error) error {
os.Setenv("CNI_COMMAND", "STATUS")
os.Setenv("CNI_PATH", os.Getenv("PATH"))
os.Setenv("CNI_NETNS_OVERRIDE", "1")
defer envCleanup()

return f()
}
102 changes: 102 additions & 0 deletions pkg/testutils/dhcp4server/leasepool/lease.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package leasepool
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand, this code comes from https://github.com/d2g/dhcp4server/, licensed as Mozilla Public License 2.0(MPL2.0) and it includes this code, not vendoring.

Can we copy this file without LICENSE notification? (I mean that dhcp4server is MPL2.0, not APL2.0). Should we add MPL2.0 in LICENSE file?


import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"net"
"time"
)

type LeaseStatus int

const (
Free LeaseStatus = 0
Reserved LeaseStatus = 1
Active LeaseStatus = 2
)

type Lease struct {
IP net.IP // The IP of the Lease
Status LeaseStatus // Are Reserved, Active or Free
MACAddress net.HardwareAddr // Mac Address of the Device
ClientID []byte // ClientID of the request
Hostname string // Hostname From option 12
Expiry time.Time // Expiry Time
}

// leaseMarshal is a mirror of Lease used for marshalling, since
// net.HardwareAddr has no native marshalling capability.
type leaseMarshal struct {
IP string
Status int
MACAddress string
ClientID string
Hostname string
Expiry time.Time
}

func (l Lease) MarshalJSON() ([]byte, error) {
return json.Marshal(leaseMarshal{
IP: l.IP.String(),
Status: int(l.Status),
MACAddress: l.MACAddress.String(),
ClientID: hex.EncodeToString(l.ClientID),
Hostname: l.Hostname,
Expiry: l.Expiry,
})
}

func (l *Lease) UnmarshalJSON(data []byte) error {
stringUnMarshal := leaseMarshal{}
err := json.Unmarshal(data, &stringUnMarshal)
if err != nil {
return err
}

l.IP = net.ParseIP(stringUnMarshal.IP)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe check if the parse failed here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole file is just a copy-paste of an old dependency. It's silly code just for testing; I didn't want to fix it up.

l.Status = LeaseStatus(stringUnMarshal.Status)
if stringUnMarshal.MACAddress != "" {
l.MACAddress, err = net.ParseMAC(stringUnMarshal.MACAddress)
if err != nil {
return fmt.Errorf("error parsing MAC address: %v", err)
}
}
l.ClientID, err = hex.DecodeString(stringUnMarshal.ClientID)
if err != nil {
return fmt.Errorf("error decoding clientID: %v", err)
}
l.Hostname = stringUnMarshal.Hostname
l.Expiry = stringUnMarshal.Expiry

return nil
}

func (l Lease) Equal(other Lease) bool {
if !l.IP.Equal(other.IP) {
return false
}

if int(l.Status) != int(other.Status) {
return false
}

if l.MACAddress.String() != other.MACAddress.String() {
return false
}

if !bytes.Equal(l.ClientID, other.ClientID) {
return false
}

if l.Hostname != other.Hostname {
return false
}

if !l.Expiry.Equal(other.Expiry) {
return false
}

return true
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import (
* Lease.IP is the Key.
*/
type LeasePool interface {
//Add A Lease To The Pool
// Add A Lease To The Pool
AddLease(Lease) error

//Remove
// Remove
RemoveLease(net.IP) error

//Remove All Leases from the Pool (Required for Persistant LeaseManagers)
// Remove All Leases from the Pool (Required for Persistent LeaseManagers)
PurgeLeases() error

/*
Expand All @@ -25,7 +25,7 @@ type LeasePool interface {
*/
GetLease(net.IP) (bool, Lease, error)

//Get the lease already in use by that hardware address and/or client identifier.
// Get the lease already in use by that hardware address and/or client identifier.
GetLeaseForClient(net.HardwareAddr, []byte) (bool, Lease, error)

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ package memorypool
import (
"bytes"
"errors"
"github.com/d2g/dhcp4server/leasepool"
"net"
"sync"

"github.com/containernetworking/plugins/pkg/testutils/dhcp4server/leasepool"
)

type MemoryPool struct {
pool []leasepool.Lease
poolLock sync.Mutex
}

//Add A Lease To The Pool
// Add A Lease To The Pool
func (t *MemoryPool) AddLease(newLease leasepool.Lease) error {
t.poolLock.Lock()
defer t.poolLock.Unlock()
Expand All @@ -24,7 +25,7 @@ func (t *MemoryPool) AddLease(newLease leasepool.Lease) error {

for i := range t.pool {
if t.pool[i].IP.Equal(newLease.IP) {
//Lease Already Exists In Pool
// Lease Already Exists In Pool
return errors.New("Error: Lease IP \"" + newLease.IP.String() + "\" alreay exists in Pool")
}
}
Expand All @@ -33,18 +34,18 @@ func (t *MemoryPool) AddLease(newLease leasepool.Lease) error {
return nil
}

//Remove a Lease From The Pool
// Remove a Lease From The Pool
func (t *MemoryPool) RemoveLease(leaseIP net.IP) error {
t.poolLock.Lock()
defer t.poolLock.Unlock()

for i := range t.pool {
if t.pool[i].IP.Equal(leaseIP) {

//Move the Last Element to This Position.
// Move the Last Element to This Position.
t.pool[i] = t.pool[len(t.pool)-1]

//Shortern the Pool By One.
// Shortern the Pool By One.
t.pool = t.pool[0:(len(t.pool) - 1)]
return nil
}
Expand All @@ -53,7 +54,7 @@ func (t *MemoryPool) RemoveLease(leaseIP net.IP) error {
return errors.New("Error: Lease IP \"" + leaseIP.String() + "\" Is Not In The Pool")
}

//Remove All Leases from the Pool (Required for Persistant LeaseManagers)
// Remove All Leases from the Pool (Required for Persistent LeaseManagers)
func (t *MemoryPool) PurgeLeases() error {
t.poolLock.Lock()
defer t.poolLock.Unlock()
Expand Down Expand Up @@ -89,7 +90,7 @@ func makeKey(macAddress net.HardwareAddr, clientID []byte) []byte {
return key
}

//Get the lease already in use by that hardware address and/or client identifier.
// Get the lease already in use by that hardware address and/or client identifier.
func (t *MemoryPool) GetLeaseForClient(macAddress net.HardwareAddr, clientID []byte) (bool, leasepool.Lease, error) {
t.poolLock.Lock()
defer t.poolLock.Unlock()
Expand All @@ -113,15 +114,15 @@ func (t *MemoryPool) GetNextFreeLease() (bool, leasepool.Lease, error) {
t.poolLock.Lock()
defer t.poolLock.Unlock()

//Loop Through the elements backwards.
// Loop Through the elements backwards.
for i := (len(t.pool) - 1); i >= 0; i-- {
//If the Lease Is Free
// If the Lease Is Free
if t.pool[i].Status == leasepool.Free {
//Take the Element
// Take the Element
iLease := t.pool[i]
//Shrink the Pool By 1
// Shrink the Pool By 1
t.pool = t.pool[:(len(t.pool) - 1)]
//Place the Lease At the Begining (This saves us having some sort of counter...)
// Place the Lease At the Beginning (This saves us having some sort of counter...)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Place the Lease At the Beginning (This saves us having some sort of counter...)
// Place the Lease at the beginning (This saves us having some sort of counter...)

ultra-nit

t.pool = append([]leasepool.Lease{iLease}, t.pool...)
return true, iLease, nil
}
Expand Down
Loading
Loading