dhcp ipam: support customizing dhcp options
Signed-off-by: SilverBut <SilverBut@users.noreply.github.com>
This commit is contained in:
@ -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)
|
||||
|
Reference in New Issue
Block a user