mirror of
https://github.com/danderson/netboot.git
synced 2025-10-15 17:41:38 +02:00
added support for generation of "dns servers" option
This commit is contained in:
parent
b78d515ee1
commit
6c11f1e722
@ -20,10 +20,6 @@ import (
|
||||
"go.universe.tf/netboot/third_party/ipxe"
|
||||
)
|
||||
|
||||
// qemu-system-x86_64 -L . --bios /usr/share/edk2-firmware/ipv6/OVMF.fd -netdev bridge,br=br1,id=net0 -device virtio-net-pci,netdev=net0
|
||||
// sudo ./pixiecore bootipv6 --listen-addr=2001:db8:f00f:cafe::4/64 --httpboot-url=http://[2001:db8:f00f:cafe::4]/bootx64.efi --ipxe-url=http://[2001:db8:f00f:cafe::4]/script.ipxe
|
||||
// sudo ./pixiecore ipv6api --listen-addr=2001:db8:f00f:cafe::4 --api-request-url=http://[2001:db8:f00f:cafe::4]:8888
|
||||
|
||||
func main() {
|
||||
cli.Ipxe[pixiecore.FirmwareX86PC] = ipxe.MustAsset("undionly.kpxe")
|
||||
cli.Ipxe[pixiecore.FirmwareEFI32] = ipxe.MustAsset("ipxe-i386.efi")
|
||||
|
@ -7,28 +7,31 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"bytes"
|
||||
"net"
|
||||
)
|
||||
|
||||
type BootConfiguration interface {
|
||||
GetBootUrl(id []byte, clientArchType uint16) ([]byte, error)
|
||||
GetPreference() []byte
|
||||
GetRecursiveDns() []byte
|
||||
GetRecursiveDns() []net.IP
|
||||
}
|
||||
|
||||
type StaticBootConfiguration struct {
|
||||
HttpBootUrl []byte
|
||||
IPxeBootUrl []byte
|
||||
RecursiveDns []byte
|
||||
Preference []byte
|
||||
UsePreference bool
|
||||
HttpBootUrl []byte
|
||||
IPxeBootUrl []byte
|
||||
RecursiveDns []net.IP
|
||||
Preference []byte
|
||||
UsePreference bool
|
||||
}
|
||||
|
||||
func MakeStaticBootConfiguration(httpBootUrl, ipxeBootUrl string, preference uint8, usePreference bool) *StaticBootConfiguration {
|
||||
func MakeStaticBootConfiguration(httpBootUrl, ipxeBootUrl string, preference uint8, usePreference bool,
|
||||
dnsServerAddresses []net.IP) *StaticBootConfiguration {
|
||||
ret := &StaticBootConfiguration{HttpBootUrl: []byte(httpBootUrl), IPxeBootUrl: []byte(ipxeBootUrl), UsePreference: usePreference}
|
||||
if usePreference {
|
||||
ret.Preference = make([]byte, 1)
|
||||
ret.Preference[0] = byte(preference)
|
||||
}
|
||||
ret.RecursiveDns = dnsServerAddresses
|
||||
return ret
|
||||
}
|
||||
|
||||
@ -43,19 +46,20 @@ func (bc *StaticBootConfiguration) GetPreference() []byte {
|
||||
return bc.Preference
|
||||
}
|
||||
|
||||
func (bc *StaticBootConfiguration) GetRecursiveDns() []byte {
|
||||
func (bc *StaticBootConfiguration) GetRecursiveDns() []net.IP {
|
||||
return bc.RecursiveDns
|
||||
}
|
||||
|
||||
type ApiBootConfiguration struct {
|
||||
client *http.Client
|
||||
urlPrefix string
|
||||
RecursiveDns []byte
|
||||
Preference []byte
|
||||
UsePreference bool
|
||||
client *http.Client
|
||||
urlPrefix string
|
||||
RecursiveDns []net.IP
|
||||
Preference []byte
|
||||
UsePreference bool
|
||||
}
|
||||
|
||||
func MakeApiBootConfiguration(url string, timeout time.Duration, preference uint8, usePreference bool) *ApiBootConfiguration {
|
||||
func MakeApiBootConfiguration(url string, timeout time.Duration, preference uint8, usePreference bool,
|
||||
dnsServerAddresses []net.IP) *ApiBootConfiguration {
|
||||
if !strings.HasSuffix(url, "/") {
|
||||
url += "/"
|
||||
}
|
||||
@ -68,6 +72,7 @@ func MakeApiBootConfiguration(url string, timeout time.Duration, preference uint
|
||||
ret.Preference = make([]byte, 1)
|
||||
ret.Preference[0] = byte(preference)
|
||||
}
|
||||
ret.RecursiveDns = dnsServerAddresses
|
||||
|
||||
return ret
|
||||
}
|
||||
@ -110,6 +115,6 @@ func (bc *ApiBootConfiguration) GetPreference() []byte {
|
||||
return bc.Preference
|
||||
}
|
||||
|
||||
func (bc *ApiBootConfiguration) GetRecursiveDns() []byte {
|
||||
func (bc *ApiBootConfiguration) GetRecursiveDns() []net.IP {
|
||||
return bc.RecursiveDns
|
||||
}
|
||||
|
@ -158,6 +158,14 @@ func MakeStatusOption(statusCode uint16, message string) *Option {
|
||||
return MakeOption(OptStatusCode, value)
|
||||
}
|
||||
|
||||
func MakeDNSServersOption(addresses []net.IP) *Option {
|
||||
value := make([]byte, 16*len(addresses))
|
||||
for i, dnsAddress := range addresses {
|
||||
copy(value[i*16:], dnsAddress)
|
||||
}
|
||||
return MakeOption(OptRecursiveDns, value)
|
||||
}
|
||||
|
||||
func (o Options) Marshal() ([]byte, error) {
|
||||
buffer := bytes.NewBuffer(make([]byte, 0, 1446))
|
||||
for _, multipleOptions := range(o) {
|
||||
|
@ -102,3 +102,22 @@ func TestUnmarshalFailsIfOROLengthIsOdd(t *testing.T) {
|
||||
t.Fatalf("Parsing options should fail: option request for options has odd length.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeDNSServersOption(t *testing.T) {
|
||||
expectedAddress1 := net.ParseIP("2001:db8:f00f:cafe::99")
|
||||
expectedAddress2 := net.ParseIP("2001:db8:f00f:cafe::9A")
|
||||
dnsServersOption := MakeDNSServersOption([]net.IP{expectedAddress1, expectedAddress2})
|
||||
|
||||
if dnsServersOption.Id != OptRecursiveDns {
|
||||
t.Fatalf("Expected option id %d, got %d", OptRecursiveDns, dnsServersOption.Id)
|
||||
}
|
||||
if dnsServersOption.Length != 32 {
|
||||
t.Fatalf("Expected length 32 bytes, got %d", dnsServersOption.Length)
|
||||
}
|
||||
if string(dnsServersOption.Value[0:16]) != string(expectedAddress1) {
|
||||
t.Fatalf("Expected dns server address %v, got %v", expectedAddress1, net.IP(dnsServersOption.Value[0:16]))
|
||||
}
|
||||
if string(dnsServersOption.Value[16:]) != string(expectedAddress2) {
|
||||
t.Fatalf("Expected dns server address %v, got %v", expectedAddress2, net.IP(dnsServersOption.Value[16:]))
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package dhcp6
|
||||
import (
|
||||
"hash/fnv"
|
||||
"encoding/binary"
|
||||
"net"
|
||||
)
|
||||
|
||||
type PacketBuilder struct {
|
||||
@ -27,7 +28,7 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio
|
||||
return b.MakeMsgAdvertiseWithNoAddrsAvailable(in.TransactionID, in.Options.ClientId(), err), err
|
||||
}
|
||||
return b.MakeMsgAdvertise(in.TransactionID, in.Options.ClientId(),
|
||||
in.Options.ClientArchType(), associations, bootFileUrl, configuration.GetPreference()), nil
|
||||
in.Options.ClientArchType(), associations, bootFileUrl, configuration.GetPreference(), configuration.GetRecursiveDns()), nil
|
||||
case MsgRequest:
|
||||
bootFileUrl, err := configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType())
|
||||
if err != nil {
|
||||
@ -35,14 +36,15 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio
|
||||
}
|
||||
associations, err := addresses.ReserveAddresses(in.Options.ClientId(), in.Options.IaNaIds())
|
||||
return b.MakeMsgReply(in.TransactionID, in.Options.ClientId(),
|
||||
in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIds()), bootFileUrl, err), err
|
||||
in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIds()), bootFileUrl,
|
||||
configuration.GetRecursiveDns(), err), err
|
||||
case MsgInformationRequest:
|
||||
bootFileUrl, err := configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b.MakeMsgInformationRequestReply(in.TransactionID, in.Options.ClientId(),
|
||||
in.Options.ClientArchType(), bootFileUrl), nil
|
||||
in.Options.ClientArchType(), bootFileUrl, configuration.GetRecursiveDns()), nil
|
||||
case MsgRelease:
|
||||
addresses.ReleaseAddresses(in.Options.ClientId(), in.Options.IaNaIds())
|
||||
return b.MakeMsgReleaseReply(in.TransactionID, in.Options.ClientId()), nil
|
||||
@ -52,7 +54,7 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio
|
||||
}
|
||||
|
||||
func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte, clientArchType uint16,
|
||||
associations []*IdentityAssociation, bootFileUrl, preference []byte) *Packet {
|
||||
associations []*IdentityAssociation, bootFileUrl, preference []byte, dnsServers []net.IP) *Packet {
|
||||
ret_options := make(Options)
|
||||
ret_options.AddOption(MakeOption(OptClientId, clientId))
|
||||
for _, association := range(associations) {
|
||||
@ -65,15 +67,13 @@ func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte,
|
||||
}
|
||||
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl))
|
||||
if preference != nil {ret_options.AddOption(MakeOption(OptPreference, preference))}
|
||||
|
||||
//ret_options.AddOption(OptRecursiveDns, net.ParseIP("2001:db8:f00f:cafe::1"))
|
||||
//ret_options.AddOption(OptBootfileParam, []byte("http://")
|
||||
ret_options.AddOption(MakeDNSServersOption(dnsServers))
|
||||
|
||||
return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options}
|
||||
}
|
||||
|
||||
func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, clientArchType uint16,
|
||||
associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileUrl []byte, err error) *Packet {
|
||||
associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileUrl []byte, dnsServers []net.IP, err error) *Packet {
|
||||
ret_options := make(Options)
|
||||
ret_options.AddOption(MakeOption(OptClientId, clientId))
|
||||
for _, association := range(associations) {
|
||||
@ -89,12 +89,13 @@ func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, cli
|
||||
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
||||
}
|
||||
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl))
|
||||
ret_options.AddOption(MakeDNSServersOption(dnsServers))
|
||||
|
||||
return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options}
|
||||
}
|
||||
|
||||
func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, clientId []byte, clientArchType uint16,
|
||||
bootFileUrl []byte) *Packet {
|
||||
bootFileUrl []byte, dnsServers []net.IP) *Packet {
|
||||
ret_options := make(Options)
|
||||
ret_options.AddOption(MakeOption(OptClientId, clientId))
|
||||
ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid))
|
||||
@ -102,6 +103,7 @@ func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, cl
|
||||
ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient
|
||||
}
|
||||
ret_options.AddOption(MakeOption(OptBootfileUrl, bootFileUrl))
|
||||
ret_options.AddOption(MakeDNSServersOption(dnsServers))
|
||||
|
||||
return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options}
|
||||
}
|
||||
|
@ -14,12 +14,13 @@ func TestMakeMsgAdvertise(t *testing.T) {
|
||||
transactionId := [3]byte{'1', '2', '3'}
|
||||
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
||||
expectedBootFileUrl := []byte("http://bootfileurl")
|
||||
expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99")
|
||||
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: expectedInterfaceId}
|
||||
|
||||
builder := MakePacketBuilder(expectedServerId, 90, 100)
|
||||
|
||||
msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation},
|
||||
expectedBootFileUrl, nil)
|
||||
expectedBootFileUrl, nil, []net.IP{expectedDnsServerIp})
|
||||
|
||||
if msg.Type != MsgAdvertise {
|
||||
t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type)
|
||||
@ -70,7 +71,7 @@ func TestShouldSetPreferenceOptionWhenSpecified(t *testing.T) {
|
||||
|
||||
expectedPreference := []byte{128}
|
||||
msg := builder.MakeMsgAdvertise([3]byte{'t', 'i', 'd'}, []byte("clientid"), 0x11,
|
||||
[]*IdentityAssociation{identityAssociation}, []byte("http://bootfileurl"), expectedPreference)
|
||||
[]*IdentityAssociation{identityAssociation}, []byte("http://bootfileurl"), expectedPreference, []net.IP{})
|
||||
|
||||
preferenceOption := msg.Options[OptPreference]
|
||||
if preferenceOption == nil {
|
||||
@ -92,7 +93,7 @@ func TestMakeMsgAdvertiseWithHttpClientArch(t *testing.T) {
|
||||
builder := MakePacketBuilder(expectedServerId, 90, 100)
|
||||
|
||||
msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x10, []*IdentityAssociation{identityAssociation},
|
||||
expectedBootFileUrl, nil)
|
||||
expectedBootFileUrl, nil, []net.IP{})
|
||||
|
||||
vendorClassOption := msg.Options[OptVendorClass]
|
||||
if vendorClassOption == nil {
|
||||
@ -158,12 +159,13 @@ func TestMakeMsgReply(t *testing.T) {
|
||||
transactionId := [3]byte{'1', '2', '3'}
|
||||
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
||||
expectedBootFileUrl := []byte("http://bootfileurl")
|
||||
expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99")
|
||||
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")}
|
||||
|
||||
builder := MakePacketBuilder(expectedServerId, 90, 100)
|
||||
|
||||
msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation},
|
||||
make([][]byte, 0), expectedBootFileUrl, nil)
|
||||
make([][]byte, 0), expectedBootFileUrl, []net.IP{expectedDnsServerIp}, nil)
|
||||
|
||||
if msg.Type != MsgReply {
|
||||
t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type)
|
||||
@ -220,7 +222,7 @@ func TestMakeMsgReplyWithHttpClientArch(t *testing.T) {
|
||||
|
||||
msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x10,
|
||||
[]*IdentityAssociation{identityAssociation}, make([][]byte, 0),
|
||||
expectedBootFileUrl, nil)
|
||||
expectedBootFileUrl, []net.IP{}, nil)
|
||||
|
||||
vendorClassOption := msg.Options[OptVendorClass]
|
||||
if vendorClassOption == nil {
|
||||
@ -248,7 +250,7 @@ func TestMakeMsgReplyWithNoAddrsAvailable(t *testing.T) {
|
||||
builder := MakePacketBuilder(expectedServerId, 90, 100)
|
||||
|
||||
msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x10,
|
||||
[]*IdentityAssociation{identityAssociation}, [][]byte{[]byte("id-2")}, expectedBootFileUrl,
|
||||
[]*IdentityAssociation{identityAssociation}, [][]byte{[]byte("id-2")}, expectedBootFileUrl, []net.IP{},
|
||||
fmt.Errorf(expectedErrorMessage))
|
||||
|
||||
iaNaOption := msg.Options[OptIaNa]
|
||||
@ -295,10 +297,12 @@ func TestMakeMsgInformationRequestReply(t *testing.T) {
|
||||
expectedServerId := []byte("serverid")
|
||||
transactionId := [3]byte{'1', '2', '3'}
|
||||
expectedBootFileUrl := []byte("http://bootfileurl")
|
||||
expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99")
|
||||
|
||||
builder := MakePacketBuilder(expectedServerId, 90, 100)
|
||||
|
||||
msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x11, expectedBootFileUrl)
|
||||
msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x11,
|
||||
expectedBootFileUrl, []net.IP{expectedDnsServerIp})
|
||||
|
||||
if msg.Type != MsgReply {
|
||||
t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type)
|
||||
@ -346,7 +350,8 @@ func TestMakeMsgInformationRequestReplyWithHttpClientArch(t *testing.T) {
|
||||
|
||||
builder := MakePacketBuilder(expectedServerId, 90, 100)
|
||||
|
||||
msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x10, expectedBootFileUrl)
|
||||
msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x10,
|
||||
expectedBootFileUrl, []net.IP{})
|
||||
|
||||
vendorClassOption := msg.Options[OptVendorClass]
|
||||
if vendorClassOption == nil {
|
||||
|
@ -6,8 +6,10 @@ import (
|
||||
"go.universe.tf/netboot/pixiecorev6"
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// pixiecore bootipv6 --listen-addr=2001:db8:f00f:cafe::4/64 --httpboot-url=http://[2001:db8:f00f:cafe::4]/bootx64.efi --ipxe-url=http://[2001:db8:f00f:cafe::4]/script.ipxe
|
||||
var bootIPv6Cmd = &cobra.Command{
|
||||
Use: "bootipv6",
|
||||
Short: "Boot a kernel and optional init ramdisks over IPv6",
|
||||
@ -50,7 +52,18 @@ var bootIPv6Cmd = &cobra.Command{
|
||||
if err != nil {
|
||||
fatalf("Error reading flag: %s", err)
|
||||
}
|
||||
s.BootConfig = dhcp6.MakeStaticBootConfiguration(httpBootUrl, ipxeUrl, preference, cmd.Flags().Changed("preference"))
|
||||
dnsServers, err := cmd.Flags().GetString("dns-servers")
|
||||
if err != nil {
|
||||
fatalf("Error reading flag: %s", err)
|
||||
}
|
||||
dnsServerAddresses := make([]net.IP, 0)
|
||||
if cmd.Flags().Changed("dns-servers") {
|
||||
for _, dnsServerAddress := range strings.Split(dnsServers, ",") {
|
||||
dnsServerAddresses = append(dnsServerAddresses, net.ParseIP(dnsServerAddress))
|
||||
}
|
||||
}
|
||||
s.BootConfig = dhcp6.MakeStaticBootConfiguration(httpBootUrl, ipxeUrl, preference,
|
||||
cmd.Flags().Changed("preference"), dnsServerAddresses)
|
||||
|
||||
addressPoolStart, err := cmd.Flags().GetString("address-pool-start")
|
||||
if err != nil {
|
||||
@ -80,6 +93,7 @@ func serverv6ConfigFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringP("address-pool-start", "", "2001:db8:f00f:cafe:ffff::100", "Starting ip of the address pool, e.g. 2001:db8:f00f:cafe:ffff::100")
|
||||
cmd.Flags().Uint64("address-pool-size", 50, "Address pool size")
|
||||
cmd.Flags().Uint32("address-pool-lifetime", 1850, "Address pool ip valid lifetime in seconds")
|
||||
cmd.Flags().StringP("dns-servers", "", "", "Comma separated list of one or more dns server addresses")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -7,8 +7,11 @@ import (
|
||||
"go.universe.tf/netboot/dhcp6"
|
||||
"time"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// pixiecore ipv6api --listen-addr=2001:db8:f00f:cafe::4 --api-request-url=http://[2001:db8:f00f:cafe::4]:8888
|
||||
|
||||
var ipv6ApiCmd = &cobra.Command{
|
||||
Use: "ipv6api",
|
||||
Short: "Boot a kernel and optional init ramdisks over IPv6 using api",
|
||||
@ -46,7 +49,18 @@ var ipv6ApiCmd = &cobra.Command{
|
||||
if err != nil {
|
||||
fatalf("Error reading flag: %s", err)
|
||||
}
|
||||
s.BootConfig = dhcp6.MakeApiBootConfiguration(apiUrl, apiTimeout, preference, cmd.Flags().Changed("preference"))
|
||||
dnsServers, err := cmd.Flags().GetString("dns-servers")
|
||||
if err != nil {
|
||||
fatalf("Error reading flag: %s", err)
|
||||
}
|
||||
dnsServerAddresses := make([]net.IP, 0)
|
||||
if cmd.Flags().Changed("dns-servers") {
|
||||
for _, dnsServerAddress := range strings.Split(dnsServers, ",") {
|
||||
dnsServerAddresses = append(dnsServerAddresses, net.ParseIP(dnsServerAddress))
|
||||
}
|
||||
}
|
||||
s.BootConfig = dhcp6.MakeApiBootConfiguration(apiUrl, apiTimeout, preference,
|
||||
cmd.Flags().Changed("preference"), dnsServerAddresses)
|
||||
|
||||
addressPoolStart, err := cmd.Flags().GetString("address-pool-start")
|
||||
if err != nil {
|
||||
@ -76,6 +90,7 @@ func serverv6ApiConfigFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().StringP("address-pool-start", "", "2001:db8:f00f:cafe:ffff::100", "Starting ip of the address pool, e.g. 2001:db8:f00f:cafe:ffff::100")
|
||||
cmd.Flags().Uint64("address-pool-size", 50, "Address pool size")
|
||||
cmd.Flags().Uint32("address-pool-lifetime", 1850, "Address pool ip address valid lifetime in seconds")
|
||||
cmd.Flags().StringP("dns-servers", "", "", "Comma separated list of one or more dns server addresses")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user