fix: dhcpv6 client id change by slice overwritten (#22905)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2025-07-16 16:19:06 +08:00
committed by GitHub
parent 2ef73f146b
commit 49178a2ed4
12 changed files with 258 additions and 117 deletions

View File

@@ -119,6 +119,8 @@ var (
"platform_names",
"enable_change_owner_auto_rename",
"default_handlers_whitelist_user_agents",
"metadata_server_ip4s",
"metadata_server_ip6s",
},
}

View File

@@ -15,6 +15,7 @@
package options
import (
"reflect"
"sort"
"yunion.io/x/log"
@@ -22,6 +23,7 @@ import (
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/util/netutils2"
)
func OnBaseOptionsChange(oOpts, nOpts interface{}) bool {
@@ -63,6 +65,14 @@ func OnBaseOptionsChange(oOpts, nOpts interface{}) bool {
if oldOpts.ApiServer != newOpts.ApiServer {
log.Debugf("api_server changed from %s to %s", oldOpts.ApiServer, newOpts.ApiServer)
}
if !reflect.DeepEqual(oldOpts.MetadataServerIp4s, newOpts.MetadataServerIp4s) {
netutils2.SetIp4MetadataServers(newOpts.MetadataServerIp4s)
log.Debugf("Metadata server IPv4 address changed to %s", newOpts.MetadataServerIp4s)
}
if !reflect.DeepEqual(oldOpts.MetadataServerIp6s, newOpts.MetadataServerIp6s) {
netutils2.SetIp6MetadataServers(newOpts.MetadataServerIp6s)
log.Debugf("Metadata server IPv6 address changed to %s", newOpts.MetadataServerIp6s)
}
if oldOpts.TaskWorkerCount != newOpts.TaskWorkerCount {
consts.SetTaskWorkerCount(newOpts.TaskWorkerCount)
}

View File

@@ -43,6 +43,7 @@ import (
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/util/atexit"
"yunion.io/x/onecloud/pkg/util/fileutils2"
"yunion.io/x/onecloud/pkg/util/netutils2"
)
const (
@@ -116,6 +117,9 @@ type BaseOptions struct {
CustomizedPrivatePrefixes []string `help:"customized private prefixes"`
MetadataServerIp4s []string `help:"metadata server IPv4 addresses, default is 169.254.169.254" default:"169.254.169.254"`
MetadataServerIp6s []string `help:"metadata server IPv6 addresses, default is fd00:ec2::254" default:"'fd00:ec2::254'"`
structarg.BaseOptions
GlobalHTTPProxy string `help:"Global http proxy"`
@@ -365,6 +369,8 @@ func parseOptions(optStruct interface{}, args []string, configFileName string, s
consts.SetServiceName(optionsRef.ApplicationID)
httperrors.SetTimeZone(optionsRef.TimeZone)
netutils2.SetIp4MetadataServers(optionsRef.MetadataServerIp4s)
netutils2.SetIp6MetadataServers(optionsRef.MetadataServerIp6s)
// log configuration
log.SetVerboseLevel(int32(optionsRef.LogVerboseLevel))

View File

@@ -464,28 +464,6 @@ func (l *sLinuxRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics []*ty
log.Errorf("rootFs.GenerateSshHostKeys fail %s", err)
}
}
// force dhclient for NetworkManager
{
err := forceNetworkManagerDhclient(rootFs)
if err != nil {
log.Errorf("force NetworkManager dhclient fail %s", err)
}
}
return nil
}
func forceNetworkManagerDhclient(rootFs IDiskPartition) error {
const nmConfPath = "/etc/NetworkManager/conf.d"
if !rootFs.Exists(nmConfPath, false) {
return nil
}
dhcpConfPath := path.Join(nmConfPath, "dhcp-client.conf")
content := `[main]
dhcp=dhclient
`
if err := rootFs.FilePutContents(dhcpConfPath, content, false, false); err != nil {
return errors.Wrapf(err, "write %s fail", dhcpConfPath)
}
return nil
}

View File

@@ -34,7 +34,7 @@ func TestNewNetplanConfig(t *testing.T) {
{
mainIp: "10.168.222.175",
nics: []*types.SServerNic{
&types.SServerNic{
{
Name: "eth0",
Index: 0,
Bridge: "br0",
@@ -60,7 +60,7 @@ func TestNewNetplanConfig(t *testing.T) {
LinkUp: true,
},
&types.SServerNic{
{
Name: "eth1",
Index: 1,
Bridge: "br0",
@@ -93,14 +93,14 @@ func TestNewNetplanConfig(t *testing.T) {
Version: 2,
Renderer: netplan.NetworkRendererNetworkd,
Ethernets: map[string]*netplan.EthernetConfig{
"eth0": &netplan.EthernetConfig{
"eth0": {
MacAddress: "00:24:c7:16:80:f2",
Match: &netplan.EthernetConfigMatch{
MacAddress: "00:24:c7:16:80:f2",
},
Mtu: 1500,
},
"eth1": &netplan.EthernetConfig{
"eth1": {
MacAddress: "00:24:c7:16:80:f3",
Match: &netplan.EthernetConfigMatch{
MacAddress: "00:24:c7:16:80:f3",
@@ -109,7 +109,7 @@ func TestNewNetplanConfig(t *testing.T) {
},
},
Bonds: map[string]*netplan.Bond{
"bond0": &netplan.Bond{
"bond0": {
EthernetConfig: netplan.EthernetConfig{
Addresses: []string{
"10.168.222.175/24",
@@ -150,7 +150,7 @@ func TestNewNetplanConfig(t *testing.T) {
{
mainIp: "10.168.22.175",
nics: []*types.SServerNic{
&types.SServerNic{
{
Name: "eth0",
Index: 0,
Bridge: "br0",
@@ -176,7 +176,7 @@ func TestNewNetplanConfig(t *testing.T) {
LinkUp: true,
},
&types.SServerNic{
{
Name: "eth1",
Index: 1,
Bridge: "br0",
@@ -209,14 +209,14 @@ func TestNewNetplanConfig(t *testing.T) {
Version: 2,
Renderer: netplan.NetworkRendererNetworkd,
Ethernets: map[string]*netplan.EthernetConfig{
"eth0": &netplan.EthernetConfig{
"eth0": {
MacAddress: "00:24:c7:16:80:f2",
Match: &netplan.EthernetConfigMatch{
MacAddress: "00:24:c7:16:80:f2",
},
Mtu: 1500,
},
"eth1": &netplan.EthernetConfig{
"eth1": {
MacAddress: "00:24:c7:16:80:f3",
Match: &netplan.EthernetConfigMatch{
MacAddress: "00:24:c7:16:80:f3",
@@ -225,7 +225,7 @@ func TestNewNetplanConfig(t *testing.T) {
},
},
Bonds: map[string]*netplan.Bond{
"bond0": &netplan.Bond{
"bond0": {
EthernetConfig: netplan.EthernetConfig{
Addresses: []string{
"10.168.222.175/24",
@@ -260,7 +260,7 @@ func TestNewNetplanConfig(t *testing.T) {
mainIp: "10.168.22.175",
mainIp6: "2001:db8::23",
nics: []*types.SServerNic{
&types.SServerNic{
{
Name: "eth0",
Index: 0,
Bridge: "br0",
@@ -290,7 +290,7 @@ func TestNewNetplanConfig(t *testing.T) {
Masklen6: 64,
Gateway6: "2001:db8::1",
},
&types.SServerNic{
{
Name: "eth1",
Index: 1,
Bridge: "br0",
@@ -323,14 +323,14 @@ func TestNewNetplanConfig(t *testing.T) {
Version: 2,
Renderer: netplan.NetworkRendererNetworkd,
Ethernets: map[string]*netplan.EthernetConfig{
"eth0": &netplan.EthernetConfig{
"eth0": {
MacAddress: "00:24:c7:16:80:f2",
Match: &netplan.EthernetConfigMatch{
MacAddress: "00:24:c7:16:80:f2",
},
Mtu: 1500,
},
"eth1": &netplan.EthernetConfig{
"eth1": {
MacAddress: "00:24:c7:16:80:f3",
Match: &netplan.EthernetConfigMatch{
MacAddress: "00:24:c7:16:80:f3",
@@ -339,7 +339,7 @@ func TestNewNetplanConfig(t *testing.T) {
},
},
Bonds: map[string]*netplan.Bond{
"bond0": &netplan.Bond{
"bond0": {
EthernetConfig: netplan.EthernetConfig{
Addresses: []string{
"10.168.222.175/24",
@@ -362,11 +362,6 @@ func TestNewNetplanConfig(t *testing.T) {
To: "fd00:ec2::254/128",
Via: "::",
},
{
Metric: 0,
To: "fe80::a9fe:a9fe/128",
Via: "::",
},
},
},
Interfaces: []string{

View File

@@ -22,7 +22,6 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
@@ -271,36 +270,11 @@ func getGuestConfig(
conf.Routes6 = route6
if len(nicdesc.Dns) > 0 {
conf.DNSServers = make([]net.IP, 0)
conf.DNSServers6 = make([]net.IP, 0)
for _, dns := range strings.Split(nicdesc.Dns, ",") {
if regutils.MatchIP4Addr(dns) {
conf.DNSServers = append(conf.DNSServers, net.ParseIP(dns))
} else if regutils.MatchIP6Addr(dns) {
conf.DNSServers6 = append(conf.DNSServers6, net.ParseIP(dns))
}
}
conf.DNSServers, conf.DNSServers6 = netutils2.SplitV46Addr2IP(nicdesc.Dns)
}
if len(nicdesc.Ntp) > 0 {
conf.NTPServers = make([]net.IP, 0)
conf.NTPServers6 = make([]net.IP, 0)
for _, ntp := range strings.Split(nicdesc.Ntp, ",") {
if regutils.MatchIP4Addr(ntp) {
conf.NTPServers = append(conf.NTPServers, net.ParseIP(ntp))
} else if regutils.MatchIP6Addr(ntp) {
conf.NTPServers6 = append(conf.NTPServers6, net.ParseIP(ntp))
} else if regutils.MatchDomainName(ntp) {
ntpAddrs, _ := net.LookupHost(ntp)
for _, ntpAddr := range ntpAddrs {
if regutils.MatchIP4Addr(ntpAddr) {
conf.NTPServers = append(conf.NTPServers, net.ParseIP(ntpAddr))
} else if regutils.MatchIP6Addr(ntpAddr) {
conf.NTPServers6 = append(conf.NTPServers6, net.ParseIP(ntpAddr))
}
}
}
}
conf.NTPServers, conf.NTPServers6 = netutils2.SplitV46Addr2IP(nicdesc.Ntp)
}
if nicdesc.Mtu > 0 {

View File

@@ -25,6 +25,7 @@ import (
"yunion.io/x/onecloud/pkg/hostman/options"
"yunion.io/x/onecloud/pkg/util/icmp6"
"yunion.io/x/onecloud/pkg/util/netutils2"
)
type sRARequest struct {
@@ -72,8 +73,8 @@ func (s *SGuestDHCP6Server) handleNeighborAdvertisement(msg *icmp6.SNeighborAdve
func (s *SGuestDHCP6Server) requestGatewayMac(gwIP net.IP, vlanId uint16) {
// Solicited-Node Multicast Address, FF02::1:FF00:0/104, 33:33:ff:00:00:00
destIP := net.IP{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, gwIP[13], gwIP[14], gwIP[15]}
destMac := net.HardwareAddr{0x33, 0x33, 0xff, gwIP[13], gwIP[14], gwIP[15]}
destIP := netutils2.IP2SolicitMcastIP(gwIP)
destMac := netutils2.IP2SolicitMcastMac(gwIP)
ns := &icmp6.SNeighborSolicitation{
SBaseICMP6Message: icmp6.SBaseICMP6Message{
@@ -112,9 +113,9 @@ func (s *SGuestDHCP6Server) sendRouterAdvertisement(solicitation *icmp6.SRouterS
gwMac := gwMacObj.(net.HardwareAddr)
pref := icmp6.PreferenceMedium
if conf.IsDefaultGW {
pref = icmp6.PreferenceHigh
}
//if conf.IsDefaultGW {
// pref = icmp6.PreferenceHigh
//}
_, ipnet, err := net.ParseCIDR(fmt.Sprintf("%s/%d", conf.ClientIP6, conf.PrefixLen6))
if err != nil {
@@ -170,7 +171,7 @@ func (s *SGuestDHCP6Server) sendRouterAdvertisement(solicitation *icmp6.SRouterS
RouteLifetime: 9000,
Prefix: route.Prefix,
PrefixLen: route.PrefixLen,
Preference: icmp6.PreferenceMedium,
Preference: pref,
})
}
}

View File

@@ -366,11 +366,9 @@ func NewNIC(desc string) (*SNIC, error) {
}
}
if len(nic.Ip) > 0 {
nic.dhcpServer, err = hostdhcp.NewGuestDHCPServer(nic.Bridge, options.HostOptions.DhcpServerPort, relayConf)
if err != nil {
return nil, errors.Wrapf(err, "NewGuestDHCPServer(%s, %d, %#v)", nic.Bridge, options.HostOptions.DhcpServerPort, relayConf)
}
nic.dhcpServer, err = hostdhcp.NewGuestDHCPServer(nic.Bridge, options.HostOptions.DhcpServerPort, relayConf)
if err != nil {
return nil, errors.Wrapf(err, "NewGuestDHCPServer(%s, %d, %#v)", nic.Bridge, options.HostOptions.DhcpServerPort, relayConf)
}
var relayConf6 *hostdhcp.SDHCPRelayUpstream
@@ -384,12 +382,11 @@ func NewNIC(desc string) (*SNIC, error) {
}
}
if len(nic.Ip6) > 0 {
nic.dhcpServer6, err = hostdhcp.NewGuestDHCP6Server(nic.Bridge, options.HostOptions.Dhcp6ServerPort, relayConf6)
if err != nil {
return nil, errors.Wrapf(err, "NewGuestDHCP6Server(%s, %d, %#v)", nic.Bridge, options.HostOptions.Dhcp6ServerPort, relayConf6)
}
nic.dhcpServer6, err = hostdhcp.NewGuestDHCP6Server(nic.Bridge, options.HostOptions.Dhcp6ServerPort, relayConf6)
if err != nil {
return nil, errors.Wrapf(err, "NewGuestDHCP6Server(%s, %d, %#v)", nic.Bridge, options.HostOptions.Dhcp6ServerPort, relayConf6)
}
// dhcp server start after guest manager init
return nic, nil
}

View File

@@ -297,10 +297,10 @@ type Option6 struct {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
func optionToBytes(o Option6) []byte {
buf := make([]byte, 4)
buf := make([]byte, 4+len(o.Value))
binary.BigEndian.PutUint16(buf[0:2], uint16(o.Code))
binary.BigEndian.PutUint16(buf[2:4], uint16(len(o.Value)))
buf = append(buf, o.Value...)
copy(buf[4:], o.Value)
return buf
}
@@ -316,15 +316,17 @@ func (p Packet) GetOption6s() []Option6 {
options := make([]Option6, 0)
offset := 4
if p.IsRelayMsg() {
offset = 18
offset = 16*2 + 2
}
i := offset
for i < len(p) {
code := binary.BigEndian.Uint16(p[i : i+2])
length := binary.BigEndian.Uint16(p[i+2 : i+4])
value := make([]byte, length)
copy(value, p[i+4:i+4+int(length)])
options = append(options, Option6{
Code: OptionCode6(code),
Value: p[i+4 : i+4+int(length)],
Value: value,
})
i += 4 + int(length)
}
@@ -377,13 +379,25 @@ func makeIAAddr(ip net.IP, preferLT, validLT uint32, opts []Option6) []byte {
}
func responseIANA(buf []byte, opts []Option6) []byte {
if len(buf) > 12 {
// IA_NA structure: IAID (4 bytes) + T1 (4 bytes) + T2 (4 bytes)
// Preserve the original IAID, T1, and T2 values from the client request
if len(buf) < 12 {
// If buffer is too short, pad with zeros
padding := make([]byte, 12-len(buf))
buf = append(buf, padding...)
} else if len(buf) > 12 {
// If buffer is too long, truncate to 12 bytes (IAID + T1 + T2)
buf = buf[:12]
}
// iaID := binary.BigEndian.Uint32(buf[0:4])
// t1 := binary.BigEndian.Uint32(buf[4:8])
// t2 := binary.BigEndian.Uint32(buf[8:12])
// log.Debugf("responseIANA IA_NA IAID %d t1 %d t2 %d", iaID, t1, t2)
// Log the IA_NA parameters for debugging
if len(buf) >= 12 {
iaID := binary.BigEndian.Uint32(buf[0:4])
t1 := binary.BigEndian.Uint32(buf[4:8])
t2 := binary.BigEndian.Uint32(buf[8:12])
log.Debugf("responseIANA IA_NA IAID %d t1 %d t2 %d", iaID, t1, t2)
}
buf = append(buf, optionsToBytes(opts)...)
return buf
}
@@ -414,19 +428,18 @@ func makeDHCPReplyPacket6(pkt Packet, conf *ResponseConfig, msgType MessageType)
return nil, errors.Wrapf(err, "TID6")
}
resp := NewPacket6(msgType, tid)
originOpts := pkt.GetOption6s()
getOption := func(code OptionCode6) Option6 {
for _, o := range originOpts {
getOption := func(opts []Option6, code OptionCode6) *Option6 {
for _, o := range opts {
if o.Code == code {
return o
return &o
}
}
return Option6{}
return nil
}
reqInfo := getOption(DHCPV6_OPTION_ORO)
if len(reqInfo.Value) > 0 {
reqInfo := getOption(originOpts, DHCPV6_OPTION_ORO)
if reqInfo != nil && len(reqInfo.Value) > 0 {
reqOpts := decodeRequestOptions(reqInfo.Value)
reqOptsStr := make([]string, len(reqOpts))
for i, opt := range reqOpts {
@@ -437,21 +450,35 @@ func makeDHCPReplyPacket6(pkt Packet, conf *ResponseConfig, msgType MessageType)
options := make([]Option6, 0)
reqCliID := getOption(originOpts, DHCPV6_OPTION_CLIENTID)
if reqCliID == nil {
return nil, errors.Wrapf(errors.ErrInvalidFormat, "clientID option not found")
}
// copy clientID
options = append(options, getOption(DHCPV6_OPTION_CLIENTID))
options = append(options, Option6{
Code: DHCPV6_OPTION_CLIENTID,
Value: reqCliID.Value,
})
// serverID
options = append(options, Option6{
Code: DHCPV6_OPTION_SERVERID,
Value: makeServerId(conf.InterfaceMac),
})
// Identity Association for Non-temporary Addresses Option
ianaOpt := getOption(DHCPV6_OPTION_IA_NA)
ianaOpt := getOption(originOpts, DHCPV6_OPTION_IA_NA)
if ianaOpt == nil {
return nil, errors.Wrapf(errors.ErrInvalidFormat, "IA_NA option not found")
}
// Calculate proper timing values for IA_NA
validLifetime := uint32(conf.LeaseTime.Seconds()) // Valid lifetime should be longer than preferred
preferredLifetime := validLifetime / 2
options = append(options, Option6{
Code: DHCPV6_OPTION_IA_NA,
Value: responseIANA(ianaOpt.Value, []Option6{
{
Code: DHCPV6_OPTION_IAADDR,
Value: makeIAAddr(conf.ClientIP6, uint32(conf.LeaseTime.Seconds()), uint32(conf.LeaseTime.Seconds()), []Option6{
Value: makeIAAddr(conf.ClientIP6, preferredLifetime, validLifetime, []Option6{
{
Code: DHCPV6_OPTION_STATUS_CODE,
Value: []byte{0, 0, 'S', 'u', 'c', 'c', 'e', 's', 's'},
@@ -475,6 +502,19 @@ func makeDHCPReplyPacket6(pkt Packet, conf *ResponseConfig, msgType MessageType)
})
}
// Handle rapid commit option for SOLICIT messages
if pkt.Type6() == DHCPV6_SOLICIT {
rapidCmtOpt := getOption(originOpts, DHCPV6_OPTION_RAPID_COMMIT)
if rapidCmtOpt != nil {
// Client requested rapid commit, respond with REPLY instead of ADVERTISE
msgType = DHCPV6_REPLY
options = append(options, Option6{
Code: DHCPV6_OPTION_RAPID_COMMIT,
})
}
}
resp := NewPacket6(msgType, tid)
resp = append(resp, optionsToBytes(options)...)
return resp, nil

View File

@@ -31,6 +31,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/util/procutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
var PSEUDO_VIP = "169.254.169.231"
@@ -354,6 +355,33 @@ func isExitAddress(ip string) bool {
return netutils.IsExitAddress(ipv4)
}
var (
Ip4MetadataServers = []string{
"169.254.169.254",
}
Ip6MetadataServers = []string{
"fd00:ec2::254",
}
)
func SetIp4MetadataServers(ip4s []string) {
if len(ip4s) == 0 {
ip4s = []string{
"169.254.169.254",
}
}
Ip4MetadataServers = ip4s
}
func SetIp6MetadataServers(ip6s []string) {
if len(ip6s) == 0 {
ip6s = []string{
"fd00:ec2::254",
}
}
Ip6MetadataServers = ip6s
}
func AddNicRoutes(routes4 []SRouteInfo, routes6 []SRouteInfo, nicDesc *types.SServerNic, mainIp string, mainIp6 string, nicCnt int) ([]SRouteInfo, []SRouteInfo) {
// always add static routes, even if this is the default NIC
// if mainIp == nicDesc.Ip {
@@ -373,11 +401,16 @@ func AddNicRoutes(routes4 []SRouteInfo, routes6 []SRouteInfo, nicDesc *types.SSe
if len(mainIp) > 0 && nicDesc.Ip == mainIp {
// always add 169.254.169.254 for default NIC
routes4 = addRoute(routes4, "169.254.169.254/32", "0.0.0.0")
for _, ip := range Ip4MetadataServers {
pref := ip + "/32"
routes4 = addRoute(routes4, pref, "0.0.0.0")
}
}
if len(mainIp6) > 0 && nicDesc.Ip6 == mainIp6 {
routes6 = addRoute(routes6, "fd00:ec2::254/128", "::")
routes6 = addRoute(routes6, "fe80::a9fe:a9fe/128", "::")
for _, ip6 := range Ip6MetadataServers {
pref := ip6 + "/128"
routes6 = addRoute(routes6, pref, "::")
}
}
return routes4, routes6
@@ -702,3 +735,48 @@ func TestTcpPort(ip string, port int, timeoutSecs int, tries int) error {
}
return errors.NewAggregate(errs)
}
func IP2SolicitMcastIP(ip6 net.IP) net.IP {
// Solicited-Node Multicast Address, FF02::1:FF00:0/104
return net.IP{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, ip6[13], ip6[14], ip6[15]}
}
func IP2SolicitMcastMac(ip6 net.IP) net.HardwareAddr {
// Solicited-Node Multicast Address, 33:33:ff:00:00:00
return net.HardwareAddr{0x33, 0x33, 0xff, ip6[13], ip6[14], ip6[15]}
}
func SplitV46Addr(addrsStr string) ([]string, []string) {
servers4 := stringutils2.NewSortedStrings(nil)
servers6 := stringutils2.NewSortedStrings(nil)
for _, ntp := range strings.Split(addrsStr, ",") {
if regutils.MatchIP4Addr(ntp) {
servers4 = servers4.Append(ntp)
} else if regutils.MatchIP6Addr(ntp) {
servers6 = servers6.Append(ntp)
} else if regutils.MatchDomainName(ntp) {
ntpAddrs, _ := net.LookupHost(ntp)
for _, ntpAddr := range ntpAddrs {
if regutils.MatchIP4Addr(ntpAddr) {
servers4 = servers4.Append(ntpAddr)
} else if regutils.MatchIP6Addr(ntpAddr) {
servers6 = servers6.Append(ntpAddr)
}
}
}
}
return servers4, servers6
}
func SplitV46Addr2IP(addrsStr string) ([]net.IP, []net.IP) {
addrs4, addrs6 := SplitV46Addr(addrsStr)
ip4s := make([]net.IP, len(addrs4))
ip6s := make([]net.IP, len(addrs6))
for i := range addrs4 {
ip4s[i] = net.ParseIP(addrs4[i])
}
for i := range addrs6 {
ip6s[i] = net.ParseIP(addrs6[i])
}
return ip4s, ip6s
}

View File

@@ -16,6 +16,7 @@ package netutils2
import (
"os"
"reflect"
"testing"
"yunion.io/x/jsonutils"
@@ -195,3 +196,31 @@ func TestGetRouteSpecs(t *testing.T) {
}
}
}
func TestSplitV46Addr(t *testing.T) {
cases := []struct {
in string
want4 []string
want6 []string
}{
{
in: "192.168.1.1,192.168.1.2,192.168.1.3,192.168.1.10",
want4: []string{"192.168.1.1", "192.168.1.10", "192.168.1.2", "192.168.1.3"},
want6: []string{},
},
{
in: "192.168.1.1,192.168.1.2,fe80::1,192.168.1.10",
want4: []string{"192.168.1.1", "192.168.1.10", "192.168.1.2"},
want6: []string{"fe80::1"},
},
}
for _, c := range cases {
got4, got6 := SplitV46Addr(c.in)
if !reflect.DeepEqual(got4, c.want4) {
t.Errorf("SplitV46Addr(%s) = %v, want %v", c.in, got4, c.want4)
}
if !reflect.DeepEqual(got6, c.want6) {
t.Errorf("SplitV46Addr(%s) = %v, want %v", c.in, got6, c.want6)
}
}
}

View File

@@ -26,12 +26,12 @@ import (
"yunion.io/x/ovsdb/types"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/pkg/utils"
commonapis "yunion.io/x/onecloud/pkg/apis"
apis "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/util/netutils2"
agentmodels "yunion.io/x/onecloud/pkg/vpcagent/models"
"yunion.io/x/onecloud/pkg/vpcagent/options"
"yunion.io/x/onecloud/pkg/vpcagent/ovn/mac"
@@ -438,7 +438,7 @@ func (keeper *OVNNorthboundKeeper) ClaimVpcEipgw(ctx context.Context, vpc *agent
return keeper.cli.Must(ctx, "ClaimVpcEipgw", args)
}
func formatNtpServers(srvs string) string {
/*func formatNtpServers(srvs string) string {
srv := make([]string, 0)
for _, part := range strings.Split(srvs, ",") {
part = strings.TrimSpace(part)
@@ -451,7 +451,7 @@ func formatNtpServers(srvs string) string {
}
}
return strings.Join(srv, ",")
}
}*/
func generateDhcpOptions(ctx context.Context, guestnetwork *agentmodels.Guestnetwork, opts *options.Options) *ovn_nb.DHCPOptions {
var (
@@ -516,8 +516,9 @@ func generateDhcpOptions(ctx context.Context, guestnetwork *agentmodels.Guestnet
if dnsSrvs == "" {
dnsSrvs = opts.DNSServer
}
if len(dnsSrvs) > 0 {
dhcpopts.Options["dns_server"] = "{" + dnsSrvs + "}"
dnsSrvs4List, _ := netutils2.SplitV46Addr(dnsSrvs)
if len(dnsSrvs4List) > 0 {
dhcpopts.Options["dns_server"] = "{" + strings.Join(dnsSrvs4List, ",") + "}"
}
}
{
@@ -542,9 +543,10 @@ func generateDhcpOptions(ctx context.Context, guestnetwork *agentmodels.Guestnet
ntpSrvs = strings.Join(ntp, ",")
}
}
if len(ntpSrvs) > 0 {
ntpSrvs4List, _ := netutils2.SplitV46Addr(ntpSrvs)
if len(ntpSrvs4List) > 0 {
// bug on OVN, should not use ntp server: QiuJian
dhcpopts.Options["ntp_server"] = "{" + formatNtpServers(ntpSrvs) + "}"
dhcpopts.Options["ntp_server"] = "{" + strings.Join(ntpSrvs4List, ",") + "}"
}
}
return dhcpopts
@@ -562,13 +564,42 @@ func generateDhcp6Options(ctx context.Context, guestnetwork *agentmodels.Guestne
dhcpopts := &ovn_nb.DHCPOptions{
Cidr: cidr6,
Options: map[string]string{
"server_id": dhcpMac,
// "dhcpv6_stateless": "false",
"server_id": dhcpMac,
"dhcpv6_stateless": "false",
},
ExternalIds: map[string]string{
externalKeyOcRef: ocDhcpRef,
},
}
{
dnsSrvs := network.GuestDns
if dnsSrvs == "" {
dns, err := auth.GetDNSServers(opts.Region, "")
if err != nil {
// ignore the error
// log.Errorf("auth.GetDNSServers fail %s", err)
} else {
dnsSrvs = strings.Join(dns, ",")
}
}
if dnsSrvs == "" {
dnsSrvs = opts.DNSServer
}
_, dnsSrvs6List := netutils2.SplitV46Addr(dnsSrvs)
if len(dnsSrvs6List) > 0 {
dhcpopts.Options["dns_server"] = "{" + strings.Join(dnsSrvs6List, ",") + "}"
}
}
{
dnsDomain := network.GuestDomain
if dnsDomain == "" {
dnsDomain = opts.DNSDomain
}
if len(dnsDomain) > 0 && !commonapis.IsIllegalSearchDomain(dnsDomain) {
dhcpopts.Options["domain_name"] = "\"" + dnsDomain + "\""
}
}
return dhcpopts
}