diff --git a/pkg/apis/identity/consts.go b/pkg/apis/identity/consts.go index ab427e36bc..5475d3a9d3 100644 --- a/pkg/apis/identity/consts.go +++ b/pkg/apis/identity/consts.go @@ -119,6 +119,8 @@ var ( "platform_names", "enable_change_owner_auto_rename", "default_handlers_whitelist_user_agents", + "metadata_server_ip4s", + "metadata_server_ip6s", }, } diff --git a/pkg/cloudcommon/options/changes.go b/pkg/cloudcommon/options/changes.go index fbdb99a637..7156a5d94f 100644 --- a/pkg/cloudcommon/options/changes.go +++ b/pkg/cloudcommon/options/changes.go @@ -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) } diff --git a/pkg/cloudcommon/options/options.go b/pkg/cloudcommon/options/options.go index 20ed0d7061..3537fe445d 100644 --- a/pkg/cloudcommon/options/options.go +++ b/pkg/cloudcommon/options/options.go @@ -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)) diff --git a/pkg/hostman/guestfs/fsdriver/linux.go b/pkg/hostman/guestfs/fsdriver/linux.go index d53885ee39..fd20f24375 100644 --- a/pkg/hostman/guestfs/fsdriver/linux.go +++ b/pkg/hostman/guestfs/fsdriver/linux.go @@ -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 } diff --git a/pkg/hostman/guestfs/fsdriver/netplan_test.go b/pkg/hostman/guestfs/fsdriver/netplan_test.go index ff0f78d83e..0353487d18 100644 --- a/pkg/hostman/guestfs/fsdriver/netplan_test.go +++ b/pkg/hostman/guestfs/fsdriver/netplan_test.go @@ -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{ diff --git a/pkg/hostman/hostinfo/hostdhcp/dhcpserver.go b/pkg/hostman/hostinfo/hostdhcp/dhcpserver.go index d691a96a07..5c7a69d266 100644 --- a/pkg/hostman/hostinfo/hostdhcp/dhcpserver.go +++ b/pkg/hostman/hostinfo/hostdhcp/dhcpserver.go @@ -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 { diff --git a/pkg/hostman/hostinfo/hostdhcp/icmp6handlers.go b/pkg/hostman/hostinfo/hostdhcp/icmp6handlers.go index ac055dc1c1..ecdc4328ff 100644 --- a/pkg/hostman/hostinfo/hostdhcp/icmp6handlers.go +++ b/pkg/hostman/hostinfo/hostdhcp/icmp6handlers.go @@ -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, }) } } diff --git a/pkg/hostman/hostinfo/hostinfohelper.go b/pkg/hostman/hostinfo/hostinfohelper.go index cfe1187b9a..ac29945f20 100644 --- a/pkg/hostman/hostinfo/hostinfohelper.go +++ b/pkg/hostman/hostinfo/hostinfohelper.go @@ -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 } diff --git a/pkg/util/dhcp/packet6.go b/pkg/util/dhcp/packet6.go index 1f29b881ab..64cc5cd229 100644 --- a/pkg/util/dhcp/packet6.go +++ b/pkg/util/dhcp/packet6.go @@ -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 diff --git a/pkg/util/netutils2/netutils.go b/pkg/util/netutils2/netutils.go index 7baee97af2..702716a2c3 100644 --- a/pkg/util/netutils2/netutils.go +++ b/pkg/util/netutils2/netutils.go @@ -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 +} diff --git a/pkg/util/netutils2/netutils_test.go b/pkg/util/netutils2/netutils_test.go index 223bb91dc0..616d3035bc 100644 --- a/pkg/util/netutils2/netutils_test.go +++ b/pkg/util/netutils2/netutils_test.go @@ -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) + } + } +} diff --git a/pkg/vpcagent/ovn/keeper.go b/pkg/vpcagent/ovn/keeper.go index 01acc4ee15..6d2c2484fe 100644 --- a/pkg/vpcagent/ovn/keeper.go +++ b/pkg/vpcagent/ovn/keeper.go @@ -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 }