dhcp ipam: support customizing dhcp options

Signed-off-by: SilverBut <SilverBut@users.noreply.github.com>
This commit is contained in:
SilverBut
2021-10-02 20:48:17 +08:00
parent be383cf30d
commit 2bebd89aa2
5 changed files with 169 additions and 8 deletions

View File

@ -19,6 +19,7 @@ import (
"log"
"math/rand"
"net"
"strings"
"sync"
"sync/atomic"
"time"
@ -62,6 +63,74 @@ type DHCPLease struct {
stopping uint32
stop chan struct{}
wg sync.WaitGroup
// list of requesting and providing options and if they are necessary / their value
optsRequesting map[dhcp4.OptionCode]bool
optsProviding map[dhcp4.OptionCode][]byte
}
var acquireOptionsDefault = map[dhcp4.OptionCode]bool{
dhcp4.OptionRouter: true,
dhcp4.OptionSubnetMask: true,
}
func prepareOptions(cniArgs string, ProvideOptions []ProvideOption, RequireOptions []RequireOption) (
optsRequesting map[dhcp4.OptionCode]bool, optsProviding map[dhcp4.OptionCode][]byte, err error) {
// parse CNI args
cniArgsParsed := map[string]string{}
for _, argPair := range strings.Split(cniArgs, ";") {
args := strings.SplitN(argPair, "=", 2)
if len(args) > 1 {
cniArgsParsed[args[0]] = args[1]
}
}
// parse providing options map
var optParsed dhcp4.OptionCode
optsProviding = make(map[dhcp4.OptionCode][]byte)
for _, opt := range ProvideOptions {
optParsed, err = parseOptionName(string(opt.Option))
if err != nil {
err = fmt.Errorf("Can not parse option %q: %w", opt.Option, err)
return
}
if len(opt.Value) > 0 {
if len(opt.Value) > 255 {
err = fmt.Errorf("value too long for option %q: %q", opt.Option, opt.Value)
return
}
optsProviding[optParsed] = []byte(opt.Value)
}
if value, ok := cniArgsParsed[opt.ValueFromCNIArg]; ok {
if len(value) > 255 {
err = fmt.Errorf("value too long for option %q from CNI_ARGS %q: %q", opt.Option, opt.ValueFromCNIArg, opt.Value)
return
}
optsProviding[optParsed] = []byte(value)
}
}
// parse necessary options map
optsRequesting = make(map[dhcp4.OptionCode]bool)
skipRequireDefault := false
for _, opt := range RequireOptions {
if opt.SkipDefault {
skipRequireDefault = true
}
optParsed, err = parseOptionName(string(opt.Option))
if err != nil {
err = fmt.Errorf("Can not parse option %q: %w", opt.Option, err)
return
}
optsRequesting[optParsed] = true
}
for k, v := range acquireOptionsDefault {
// only set if not skipping default and this value does not exists
if _, ok := optsRequesting[k]; !ok && !skipRequireDefault {
optsRequesting[k] = v
}
}
return
}
// AcquireLease gets an DHCP lease and then maintains it in the background
@ -69,15 +138,18 @@ type DHCPLease struct {
// calling DHCPLease.Stop()
func AcquireLease(
clientID, netns, ifName string,
optsRequesting map[dhcp4.OptionCode]bool, optsProviding map[dhcp4.OptionCode][]byte,
timeout, resendMax time.Duration, broadcast bool,
) (*DHCPLease, error) {
errCh := make(chan error, 1)
l := &DHCPLease{
clientID: clientID,
stop: make(chan struct{}),
timeout: timeout,
resendMax: resendMax,
broadcast: broadcast,
clientID: clientID,
stop: make(chan struct{}),
timeout: timeout,
resendMax: resendMax,
broadcast: broadcast,
optsRequesting: optsRequesting,
optsProviding: optsProviding,
}
log.Printf("%v: acquiring lease", clientID)
@ -139,7 +211,13 @@ func (l *DHCPLease) acquire() error {
opts := make(dhcp4.Options)
opts[dhcp4.OptionClientIdentifier] = []byte(l.clientID)
opts[dhcp4.OptionParameterRequestList] = []byte{byte(dhcp4.OptionRouter), byte(dhcp4.OptionSubnetMask)}
opts[dhcp4.OptionParameterRequestList] = []byte{}
for k := range l.optsRequesting {
opts[dhcp4.OptionParameterRequestList] = append(opts[dhcp4.OptionParameterRequestList], byte(k))
}
for k, v := range l.optsProviding {
opts[k] = v
}
pkt, err := backoffRetry(l.resendMax, func() (*dhcp4.Packet, error) {
ok, ack, err := DhcpRequest(c, opts)