| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package hostdhcp
- import (
- "net"
- "strings"
- "time"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/netutils"
- "yunion.io/x/onecloud/pkg/apis"
- "yunion.io/x/onecloud/pkg/cloudcommon/types"
- "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
- guestman "yunion.io/x/onecloud/pkg/hostman/guestman/types"
- "yunion.io/x/onecloud/pkg/hostman/options"
- "yunion.io/x/onecloud/pkg/util/dhcp"
- "yunion.io/x/onecloud/pkg/util/netutils2"
- )
- const (
- DEFAULT_DHCP_SERVER_PORT = 67
- // DEFAULT_DHCP_CLIENT_PORT = 68
- DEFAULT_DHCP_RELAY_PORT = 68
- )
- type SGuestDHCPServer struct {
- server *dhcp.DHCPServer
- relay *SDHCPRelay
- conn *dhcp.Conn
- ifaceDev *netutils2.SNetInterface
- }
- type SDHCPRelayUpstream struct {
- IP string
- Port int
- }
- func NewGuestDHCPServer(iface string, port int, relay *SDHCPRelayUpstream) (*SGuestDHCPServer, error) {
- var (
- err error
- guestdhcp = new(SGuestDHCPServer)
- )
- dev := netutils2.NewNetInterface(iface)
- if dev.GetHardwareAddr() == nil {
- return nil, errors.Wrapf(errors.ErrInvalidStatus, "iface %s no mac", iface)
- }
- guestdhcp.ifaceDev = dev
- guestdhcp.server, guestdhcp.conn, err = dhcp.NewDHCPServer2(iface, DEFAULT_DHCP_SERVER_PORT)
- if err != nil {
- return nil, errors.Wrap(err, "dhcp.NewDHCPServer2")
- }
- if relay != nil {
- guestdhcp.relay, err = NewDHCPRelay(guestdhcp.conn, relay)
- if err != nil {
- return nil, errors.Wrap(err, "NewDHCPRelay")
- }
- }
- return guestdhcp, nil
- }
- func (s *SGuestDHCPServer) Start(blocking bool) {
- log.Infof("SGuestDHCPServer %s starting (blocking: %v) ...", s.ifaceDev.String(), blocking)
- serve := func() {
- err := s.server.ListenAndServe(s)
- if err != nil {
- log.Errorf("DHCP serve error: %s", err)
- }
- }
- if blocking {
- serve()
- } else {
- go serve()
- }
- }
- func (s *SGuestDHCPServer) RelaySetup(addr string) error {
- if s.relay != nil {
- return s.relay.Setup(addr)
- }
- return nil
- }
- func gusetnetworkJsonDescToServerNic(nicdesc *types.SServerNic, guestNic *desc.SGuestNetwork) error {
- if guestNic.Routes != nil {
- if err := guestNic.Routes.Unmarshal(&nicdesc.Routes); err != nil {
- return err
- }
- }
- nicdesc.Index = int(guestNic.Index)
- nicdesc.Bridge = guestNic.Bridge
- if !apis.IsIllegalSearchDomain(guestNic.Domain) {
- nicdesc.Domain = guestNic.Domain
- }
- nicdesc.Ip = guestNic.Ip
- nicdesc.Vlan = guestNic.Vlan
- nicdesc.Driver = guestNic.Driver
- nicdesc.Masklen = int(guestNic.Masklen)
- nicdesc.Virtual = guestNic.Virtual
- if guestNic.Manual != nil {
- nicdesc.Manual = *guestNic.Manual
- }
- nicdesc.WireId = guestNic.WireId
- nicdesc.NetId = guestNic.NetId
- nicdesc.Mac = guestNic.Mac
- nicdesc.Mtu = guestNic.Mtu
- nicdesc.Dns = guestNic.Dns
- nicdesc.Ntp = guestNic.Ntp
- nicdesc.Net = guestNic.Net
- nicdesc.Interface = guestNic.Interface
- nicdesc.Gateway = guestNic.Gateway
- nicdesc.Ifname = guestNic.Ifname
- nicdesc.NicType = guestNic.NicType
- nicdesc.LinkUp = guestNic.LinkUp
- nicdesc.TeamWith = guestNic.TeamWith
- nicdesc.IsDefault = guestNic.IsDefault
- nicdesc.Ip6 = guestNic.Ip6
- nicdesc.Masklen6 = int(guestNic.Masklen6)
- nicdesc.Gateway6 = guestNic.Gateway6
- return nil
- }
- func GetMainNic(nics []*desc.SGuestNetwork) *desc.SGuestNetwork {
- for _, n := range nics {
- if n.IsDefault {
- return n
- }
- }
- for _, n := range nics {
- if n.Ip != "" && n.Gateway != "" {
- return n
- }
- }
- return nil
- }
- func GetMainNic6(nics []*desc.SGuestNetwork) *desc.SGuestNetwork {
- for _, n := range nics {
- if n.IsDefault {
- return n
- }
- }
- for _, n := range nics {
- if n.Ip6 != "" && n.Gateway6 != "" {
- return n
- }
- }
- return nil
- }
- func getGuestConfig(
- guestDesc *desc.SGuestDesc, guestNic *desc.SGuestNetwork,
- serverMac net.HardwareAddr,
- ) *dhcp.ResponseConfig {
- var nicdesc = new(types.SServerNic)
- if err := gusetnetworkJsonDescToServerNic(nicdesc, guestNic); err != nil {
- log.Errorf("failed convert server nic desc")
- return nil
- }
- var conf = new(dhcp.ResponseConfig)
- conf.InterfaceMac = serverMac
- conf.VlanId = uint16(nicdesc.Vlan)
- if len(nicdesc.Ip) > 0 {
- nicIp := nicdesc.Ip
- v4Ip, _ := netutils.NewIPV4Addr(nicIp)
- conf.ClientIP = net.ParseIP(nicdesc.Ip)
- masklen := nicdesc.Masklen
- conf.ServerIP = net.ParseIP(v4Ip.NetAddr(int8(masklen)).String())
- conf.SubnetMask = net.ParseIP(netutils2.Netlen2Mask(int(masklen)))
- conf.BroadcastAddr = v4Ip.BroadcastAddr(int8(masklen)).ToBytes()
- if nicdesc.Gateway != "" {
- conf.Gateway = net.ParseIP(nicdesc.Gateway)
- }
- }
- if len(guestDesc.Hostname) > 0 {
- conf.Hostname = guestDesc.Hostname
- } else {
- conf.Hostname = guestDesc.Name
- }
- conf.Hostname = strings.ToLower(conf.Hostname)
- conf.Domain = nicdesc.Domain
- if len(nicdesc.Ip6) > 0 {
- // ipv6
- conf.ClientIP6 = net.ParseIP(nicdesc.Ip6)
- conf.PrefixLen6 = uint8(nicdesc.Masklen6)
- if nicdesc.Gateway6 != "" {
- conf.Gateway6 = net.ParseIP(nicdesc.Gateway6)
- }
- }
- // get main ip
- guestNics := guestDesc.Nics
- mainNic := GetMainNic(guestNics)
- var mainIp string
- if mainNic != nil {
- mainIp = mainNic.Ip
- }
- mainNic6 := GetMainNic6(guestNics)
- var mainIp6 string
- if mainNic6 != nil {
- mainIp6 = mainNic6.Ip6
- }
- route4 := make([]netutils2.SRouteInfo, 0)
- route6 := make([]netutils2.SRouteInfo, 0)
- if nicdesc.IsDefault {
- conf.IsDefaultGW = true
- osName := guestDesc.OsName
- if len(osName) == 0 {
- osName = "Linux"
- }
- if conf.Gateway != nil {
- if !strings.HasPrefix(strings.ToLower(osName), "win") {
- route4 = append(route4, netutils2.SRouteInfo{
- SPrefixInfo: netutils2.SPrefixInfo{
- Prefix: net.ParseIP("0.0.0.0"),
- PrefixLen: 0,
- },
- Gateway: conf.Gateway,
- })
- }
- }
- //if conf.Gateway6 != nil {
- /*route6 = append(route6, netutils2.SRouteInfo{
- SPrefixInfo: netutils2.SPrefixInfo{
- Prefix: net.ParseIP("::"),
- PrefixLen: 0,
- },
- Gateway: conf.Gateway6,
- })*/
- //}
- }
- route4, route6 = netutils2.AddNicRoutes(route4, route6, nicdesc, mainIp, mainIp6, len(guestNics))
- conf.Routes = route4
- conf.Routes6 = route6
- if len(nicdesc.Dns) > 0 {
- conf.DNSServers, conf.DNSServers6 = netutils2.SplitV46Addr2IP(nicdesc.Dns)
- }
- if len(nicdesc.Ntp) > 0 {
- conf.NTPServers, conf.NTPServers6 = netutils2.SplitV46Addr2IP(nicdesc.Ntp)
- }
- if nicdesc.Mtu > 0 {
- conf.MTU = uint16(nicdesc.Mtu)
- }
- conf.OsName = guestDesc.OsName
- conf.LeaseTime = time.Duration(options.HostOptions.DhcpLeaseTime) * time.Second
- conf.RenewalTime = time.Duration(options.HostOptions.DhcpRenewalTime) * time.Second
- return conf
- }
- func (s *SGuestDHCPServer) getConfig(pkt dhcp.Packet) *dhcp.ResponseConfig {
- if guestman.GuestDescGetter == nil {
- return nil
- }
- var (
- mac = pkt.CHAddr().String()
- ip, port = "", ""
- isCandidate = false
- )
- guestDesc, guestNic := guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.ifaceDev.String(), isCandidate)
- if guestNic == nil {
- guestDesc, guestNic = guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.ifaceDev.String(), !isCandidate)
- }
- if guestNic != nil && !guestNic.Virtual {
- return getGuestConfig(guestDesc, guestNic, s.ifaceDev.GetHardwareAddr())
- }
- return nil
- }
- func (s *SGuestDHCPServer) IsDhcpPacket(pkt dhcp.Packet) bool {
- return pkt != nil && (pkt.Type() == dhcp.Request || pkt.Type() == dhcp.Discover)
- }
- func (s *SGuestDHCPServer) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, []string, error) {
- pkg, err := s.serveDHCPInternal(pkt, addr)
- return pkg, nil, err
- }
- func (s *SGuestDHCPServer) serveDHCPInternal(pkt dhcp.Packet, addr *net.UDPAddr) (dhcp.Packet, error) {
- if !s.IsDhcpPacket(pkt) {
- return nil, nil
- }
- var conf = s.getConfig(pkt)
- if conf != nil {
- log.Infof("Make DHCP Reply %s TO %s %s", conf.ClientIP, pkt.CHAddr(), addr.String())
- // Guest request ip
- return dhcp.MakeReplyPacket(pkt, conf)
- } else if s.relay != nil && s.relay.server != nil {
- // Host agent as dhcp relay, relay to baremetal
- return s.relay.Relay(pkt, addr)
- }
- return nil, nil
- }
|