mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-10-29 17:58:36 +08:00
fix: dhcpv6 support, phase 2 (#22852)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -1040,20 +1040,22 @@ func (b *SBaremetalInstance) GetIPMINicIPAddr() string {
|
||||
func (b *SBaremetalInstance) GetDHCPConfig(cliMac net.HardwareAddr) (*dhcp.ResponseConfig, error) {
|
||||
var nic *types.SNic
|
||||
var hostname string
|
||||
var osName string
|
||||
if b.GetServer() != nil && (b.GetTask() == nil || !b.GetTask().NeedPXEBoot()) {
|
||||
nic = b.GetServer().GetNicByMac(cliMac)
|
||||
hostname = b.GetServer().GetName()
|
||||
hostname = b.GetServer().GetHostName()
|
||||
osName = b.GetServer().GetOsName()
|
||||
} else {
|
||||
nic = b.GetNicByMac(cliMac)
|
||||
}
|
||||
if nic == nil {
|
||||
return nil, fmt.Errorf("GetNicDHCPConfig no nic found by mac: %s", cliMac)
|
||||
}
|
||||
return b.getDHCPConfig(nic, hostname, false, 0)
|
||||
return b.getDHCPConfig(nic, hostname, false, 0, osName)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetPXEDHCPConfig(arch uint16) (*dhcp.ResponseConfig, error) {
|
||||
return b.getDHCPConfig(b.GetAdminNic(), "", true, arch)
|
||||
return b.getDHCPConfig(b.GetAdminNic(), "", true, arch, "Linux")
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) getDHCPConfig(
|
||||
@@ -1061,10 +1063,14 @@ func (b *SBaremetalInstance) getDHCPConfig(
|
||||
hostName string,
|
||||
isPxe bool,
|
||||
arch uint16,
|
||||
osName string,
|
||||
) (*dhcp.ResponseConfig, error) {
|
||||
if hostName == "" {
|
||||
hostName = b.GetName()
|
||||
}
|
||||
if osName == "" {
|
||||
osName = "Linux"
|
||||
}
|
||||
serverIP, err := b.manager.Agent.GetDHCPServerIP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1078,7 +1084,7 @@ func (b *SBaremetalInstance) getDHCPConfig(
|
||||
return nil, errors.Errorf("Baremetal %s not need UEFI PXE boot", b.GetName())
|
||||
}
|
||||
}
|
||||
return GetNicDHCPConfig(nic, serverIP.String(), hostName, isPxe, arch)
|
||||
return GetNicDHCPConfig(nic, serverIP, b.manager.Agent.ListenInterface.HardwareAddr, hostName, isPxe, arch, osName)
|
||||
}
|
||||
|
||||
func (b *SBaremetalInstance) GetNotifyUrl() string {
|
||||
@@ -2550,6 +2556,22 @@ func (server *SBaremetalServer) GetName() string {
|
||||
return id
|
||||
}
|
||||
|
||||
func (server *SBaremetalServer) GetHostName() string {
|
||||
hostname, err := server.desc.GetString("hostname")
|
||||
if err != nil {
|
||||
log.Errorf("Get hostname from desc %s error: %v", server.desc.String(), err)
|
||||
}
|
||||
return hostname
|
||||
}
|
||||
|
||||
func (server *SBaremetalServer) GetOsName() string {
|
||||
osName, err := server.desc.GetString("os_name")
|
||||
if err != nil {
|
||||
log.Errorf("Get os name from desc %s error: %v", server.desc.String(), err)
|
||||
}
|
||||
return osName
|
||||
}
|
||||
|
||||
func (server *SBaremetalServer) SaveDesc(desc jsonutils.JSONObject) error {
|
||||
if desc != nil {
|
||||
server.desc = desc.(*jsonutils.JSONDict)
|
||||
|
||||
+104
-44
@@ -15,14 +15,15 @@
|
||||
package baremetal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
|
||||
o "yunion.io/x/onecloud/pkg/baremetal/options"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
@@ -31,68 +32,127 @@ import (
|
||||
|
||||
func GetNicDHCPConfig(
|
||||
n *types.SNic,
|
||||
serverIP string,
|
||||
serverIP net.IP,
|
||||
serverMac net.HardwareAddr,
|
||||
hostName string,
|
||||
isPxe bool,
|
||||
arch uint16,
|
||||
osName string,
|
||||
) (*dhcp.ResponseConfig, error) {
|
||||
if n == nil {
|
||||
return nil, fmt.Errorf("Nic is nil")
|
||||
return nil, errors.Wrap(errors.ErrEmpty, "Nic is nil")
|
||||
}
|
||||
if n.IpAddr == "" {
|
||||
return nil, fmt.Errorf("Nic no ip address")
|
||||
}
|
||||
ipAddr, err := netutils.NewIPV4Addr(n.IpAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Parse IP address error: %q", n.IpAddr)
|
||||
if n.IpAddr == "" && n.Ip6Addr == "" {
|
||||
return nil, errors.Wrap(errors.ErrEmpty, "Nic no ip or ip6 address")
|
||||
}
|
||||
|
||||
subnetMask := net.ParseIP(netutils.Masklen2Mask(n.Masklen).String())
|
||||
|
||||
routes := make([][]string, 0)
|
||||
routes4 := make([]dhcp.SRouteInfo, 0)
|
||||
routes6 := make([]dhcp.SRouteInfo, 0)
|
||||
for _, route := range n.Routes {
|
||||
routes = append(routes, []string{route[0], route[1]})
|
||||
routeInfo, err := dhcp.ParseRouteInfo([]string{route[0], route[1]})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Parse route %s error: %q", route, err)
|
||||
}
|
||||
if regutils.MatchCIDR6(route[0]) {
|
||||
routes6 = append(routes6, *routeInfo)
|
||||
} else {
|
||||
routes4 = append(routes4, *routeInfo)
|
||||
}
|
||||
}
|
||||
|
||||
parseIPs := func(ips string) []net.IP {
|
||||
ret := make([]net.IP, 0)
|
||||
iplist := strings.Split(ips, ",")
|
||||
for _, ip := range iplist {
|
||||
ret = append(ret, net.ParseIP(ip))
|
||||
if n.IsDefault == nil || *n.IsDefault {
|
||||
if n.Gateway != "" && !strings.HasPrefix(strings.ToLower(osName), "win") {
|
||||
routes4 = append(routes4, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(n.Gateway),
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
parseDomains := func(domains string) []net.IP {
|
||||
ret := make([]net.IP, 0)
|
||||
domainlist := strings.Split(domains, ",")
|
||||
for _, domain := range domainlist {
|
||||
addrs, _ := net.LookupHost(domain)
|
||||
for _, addr := range addrs {
|
||||
ret = append(ret, net.ParseIP(addr))
|
||||
}
|
||||
if n.Gateway6 != "" {
|
||||
routes6 = append(routes6, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(n.Gateway6),
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
conf := &dhcp.ResponseConfig{
|
||||
ServerIP: net.ParseIP(serverIP),
|
||||
ClientIP: net.ParseIP(ipAddr.String()),
|
||||
Gateway: net.ParseIP(n.Gateway),
|
||||
SubnetMask: subnetMask,
|
||||
BroadcastAddr: net.ParseIP(ipAddr.BroadcastAddr(n.Masklen).String()),
|
||||
DNSServers: parseIPs(n.Dns),
|
||||
NTPServers: parseDomains(n.Ntp),
|
||||
Domain: n.Domain,
|
||||
OsName: "Linux",
|
||||
Hostname: hostName,
|
||||
Routes: routes,
|
||||
LeaseTime: time.Duration(o.Options.DhcpLeaseTime) * time.Second,
|
||||
RenewalTime: time.Duration(o.Options.DhcpRenewalTime) * time.Second,
|
||||
InterfaceMac: serverMac,
|
||||
|
||||
ServerIP: serverIP,
|
||||
Domain: n.Domain,
|
||||
OsName: osName,
|
||||
Hostname: strings.ToLower(hostName),
|
||||
Routes: routes4,
|
||||
Routes6: routes6,
|
||||
LeaseTime: time.Duration(o.Options.DhcpLeaseTime) * time.Second,
|
||||
RenewalTime: time.Duration(o.Options.DhcpRenewalTime) * time.Second,
|
||||
}
|
||||
|
||||
if n.IpAddr != "" {
|
||||
ipAddr, err := netutils.NewIPV4Addr(n.IpAddr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Parse IP address error: %q", n.IpAddr)
|
||||
}
|
||||
|
||||
subnetMask := net.ParseIP(netutils.Masklen2Mask(n.Masklen).String())
|
||||
|
||||
conf.ClientIP = net.ParseIP(ipAddr.String())
|
||||
conf.SubnetMask = subnetMask
|
||||
conf.BroadcastAddr = net.ParseIP(ipAddr.BroadcastAddr(n.Masklen).String())
|
||||
conf.Gateway = net.ParseIP(n.Gateway)
|
||||
}
|
||||
if n.Ip6Addr != "" {
|
||||
ipAddr6, err := netutils.NewIPV6Addr(n.Ip6Addr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Parse IPv6 address error: %q", n.Ip6Addr)
|
||||
}
|
||||
|
||||
conf.ClientIP6 = net.ParseIP(ipAddr6.String())
|
||||
conf.PrefixLen6 = n.Masklen6
|
||||
conf.Gateway6 = net.ParseIP(n.Gateway6)
|
||||
}
|
||||
|
||||
if len(n.Dns) > 0 {
|
||||
conf.DNSServers = make([]net.IP, 0)
|
||||
conf.DNSServers6 = make([]net.IP, 0)
|
||||
for _, dns := range strings.Split(n.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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(n.Ntp) > 0 {
|
||||
conf.NTPServers = make([]net.IP, 0)
|
||||
conf.NTPServers6 = make([]net.IP, 0)
|
||||
for _, ntp := range strings.Split(n.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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if n.Mtu > 0 {
|
||||
conf.MTU = uint16(n.Mtu)
|
||||
}
|
||||
|
||||
if isPxe {
|
||||
conf.BootServer = serverIP
|
||||
conf.BootServer = serverIP.String()
|
||||
if len(o.Options.TftpBootServer) > 0 {
|
||||
conf.BootServer = o.Options.TftpBootServer
|
||||
}
|
||||
|
||||
@@ -41,4 +41,7 @@ type IBaremetalServer interface {
|
||||
GetNicByMac(mac net.HardwareAddr) *types.SNic
|
||||
|
||||
GetRootTemplateId() string
|
||||
|
||||
GetHostName() string
|
||||
GetOsName() string
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ type SNic struct {
|
||||
Bandwidth int `json:"bandwidth"`
|
||||
|
||||
Index int `json:"index"`
|
||||
|
||||
IsDefault *bool `json:"is_default"`
|
||||
}
|
||||
|
||||
type SRoute []string
|
||||
@@ -132,5 +134,7 @@ func (n SServerNic) ToNic() SNic {
|
||||
Ip6Addr: n.Ip6,
|
||||
Masklen6: uint8(n.Masklen6),
|
||||
Gateway6: n.Gateway6,
|
||||
|
||||
IsDefault: &n.IsDefault,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/coreosutils"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/fstabutils"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
@@ -930,13 +931,18 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
if mainNic != nil {
|
||||
mainIp = mainNic.Ip
|
||||
}
|
||||
mainNic6 := getMainNic6(allNics)
|
||||
var mainIp6 string
|
||||
if mainNic6 != nil {
|
||||
mainIp6 = mainNic6.Ip6
|
||||
}
|
||||
|
||||
netplanDir := "/etc/netplan"
|
||||
if rootFs.Exists(netplanDir, false) {
|
||||
for _, f := range rootFs.ListDir(netplanDir, false) {
|
||||
rootFs.Remove(filepath.Join(netplanDir, f), false)
|
||||
}
|
||||
netplanConfig := NewNetplanConfig(allNics, bondNics, mainIp)
|
||||
netplanConfig := NewNetplanConfig(allNics, bondNics, mainIp, mainIp6)
|
||||
log.Debugf("netplanConfig:\n %s", netplanConfig.YAMLString())
|
||||
if err := rootFs.FilePutContents(path.Join(netplanDir, "config.yaml"), netplanConfig.YAMLString(), false, false); err != nil {
|
||||
return errors.Wrap(err, "Put netplan config")
|
||||
@@ -978,11 +984,16 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
if nicDesc.Mtu > 0 {
|
||||
cmds.WriteString(fmt.Sprintf(" mtu %d\n", nicDesc.Mtu))
|
||||
}
|
||||
var routes = make([][]string, 0)
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
for _, r := range routes {
|
||||
cmds.WriteString(fmt.Sprintf(" up route add -net %s gw %s || true\n", r[0], r[1]))
|
||||
cmds.WriteString(fmt.Sprintf(" down route del -net %s gw %s || true\n", r[0], r[1]))
|
||||
routes4 := make([]dhcp.SRouteInfo, 0)
|
||||
routes6 := make([]dhcp.SRouteInfo, 0)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
for _, r := range routes4 {
|
||||
cmds.WriteString(fmt.Sprintf(" up ip route add %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
|
||||
cmds.WriteString(fmt.Sprintf(" down ip route del %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
|
||||
}
|
||||
for _, r := range routes6 {
|
||||
cmds.WriteString(fmt.Sprintf(" up ip -6 route add %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
|
||||
cmds.WriteString(fmt.Sprintf(" down ip -6 route del %s/%d via %s || true\n", r.Prefix, r.PrefixLen, r.Gateway))
|
||||
}
|
||||
dnslist := netutils2.GetNicDns(nicDesc)
|
||||
if len(dnslist) > 0 {
|
||||
@@ -1326,7 +1337,21 @@ func getMainNic(nics []*types.SServerNic) *types.SServerNic {
|
||||
}
|
||||
}
|
||||
for i := range nics {
|
||||
if len(nics[i].Gateway) > 0 {
|
||||
if len(nics[i].Ip) > 0 && len(nics[i].Gateway) > 0 {
|
||||
return nics[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMainNic6(nics []*types.SServerNic) *types.SServerNic {
|
||||
for i := range nics {
|
||||
if nics[i].IsDefault {
|
||||
return nics[i]
|
||||
}
|
||||
}
|
||||
for i := range nics {
|
||||
if len(nics[i].Ip6) > 0 && len(nics[i].Gateway6) > 0 {
|
||||
return nics[i]
|
||||
}
|
||||
}
|
||||
@@ -1386,6 +1411,12 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
if mainNic != nil {
|
||||
mainIp = mainNic.Ip
|
||||
}
|
||||
mainNic6 := getMainNic6(allNics)
|
||||
var mainIp6 string
|
||||
if mainNic6 != nil {
|
||||
mainIp6 = mainNic6.Ip6
|
||||
}
|
||||
|
||||
for i := range allNics {
|
||||
nicDesc := allNics[i]
|
||||
var cmds strings.Builder
|
||||
@@ -1436,7 +1467,7 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
} else if nicDesc.Manual {
|
||||
cmds.WriteString("BOOTPROTO=none\n")
|
||||
if nicDesc.VlanInterface {
|
||||
if err := r.deployVlanNetworkingScripts(rootFs, scriptPath, mainIp, nicCnt, nicDesc); err != nil {
|
||||
if err := r.deployVlanNetworkingScripts(rootFs, scriptPath, mainIp, mainIp6, nicCnt, nicDesc); err != nil {
|
||||
return errors.Wrap(err, "deployVlanNetworkingScripts")
|
||||
}
|
||||
} else {
|
||||
@@ -1452,13 +1483,14 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
cmds.WriteString(nicDesc.Gateway)
|
||||
cmds.WriteString("\n")
|
||||
}
|
||||
var routes = make([][]string, 0)
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
routes4 := make([]dhcp.SRouteInfo, 0)
|
||||
routes6 := make([]dhcp.SRouteInfo, 0)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes {
|
||||
rtbl.WriteString(r[0])
|
||||
for _, r := range routes4 {
|
||||
rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
|
||||
rtbl.WriteString(" via ")
|
||||
rtbl.WriteString(r[1])
|
||||
rtbl.WriteString(r.Gateway.String())
|
||||
rtbl.WriteString(" dev ")
|
||||
rtbl.WriteString(nicDesc.Name)
|
||||
rtbl.WriteString("\n")
|
||||
@@ -1496,12 +1528,12 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
// IPv6 support static temporarily
|
||||
// TODO
|
||||
cmds.WriteString("IPV6INIT=yes\n")
|
||||
cmds.WriteString("DHCPV6C=no\n")
|
||||
cmds.WriteString("DHCPV6C=yes\n")
|
||||
cmds.WriteString("IPV6_AUTOCONF=no\n")
|
||||
cmds.WriteString(fmt.Sprintf("IPV6ADDR=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
|
||||
if len(nicDesc.Gateway6) > 0 {
|
||||
cmds.WriteString(fmt.Sprintf("IPV6_DEFAULTGW=%s\n", nicDesc.Gateway6))
|
||||
}
|
||||
// cmds.WriteString(fmt.Sprintf("IPV6ADDR=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
|
||||
// if len(nicDesc.Gateway6) > 0 {
|
||||
// cmds.WriteString("IPV6_DEFROUTE=yes\n", nicDesc.Gateway6))
|
||||
// }
|
||||
}
|
||||
}
|
||||
var fn = fmt.Sprintf("%s/ifcfg-%s", scriptPath, nicDesc.Name)
|
||||
@@ -1513,7 +1545,7 @@ func (r *sRedhatLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *sRedhatLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scriptPath, mainIp string, nicCnt int, nicDesc *types.SServerNic) error {
|
||||
func (r *sRedhatLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scriptPath, mainIp, mainIp6 string, nicCnt int, nicDesc *types.SServerNic) error {
|
||||
if nicDesc.Vlan <= 1 {
|
||||
return nil
|
||||
}
|
||||
@@ -1544,13 +1576,14 @@ func (r *sRedhatLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, s
|
||||
cmds.WriteString(nicDesc.Gateway)
|
||||
cmds.WriteString("\n")
|
||||
}
|
||||
var routes = make([][]string, 0)
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
routes4 := make([]dhcp.SRouteInfo, 0)
|
||||
routes6 := make([]dhcp.SRouteInfo, 0)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes {
|
||||
rtbl.WriteString(r[0])
|
||||
for _, r := range routes4 {
|
||||
rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
|
||||
rtbl.WriteString(" via ")
|
||||
rtbl.WriteString(r[1])
|
||||
rtbl.WriteString(r.Gateway.String())
|
||||
rtbl.WriteString(" dev ")
|
||||
rtbl.WriteString(fmt.Sprintf("%s.%d", nicDesc.Name, nicDesc.Vlan))
|
||||
rtbl.WriteString("\n")
|
||||
|
||||
@@ -20,21 +20,22 @@ import (
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/netplan"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
|
||||
func NewNetplanConfig(allNics []*types.SServerNic, bondNics []*types.SServerNic, mainIp string) *netplan.Configuration {
|
||||
network := newNetplanNetwork(allNics, bondNics, mainIp)
|
||||
func NewNetplanConfig(allNics []*types.SServerNic, bondNics []*types.SServerNic, mainIp, mainIp6 string) *netplan.Configuration {
|
||||
network := newNetplanNetwork(allNics, bondNics, mainIp, mainIp6)
|
||||
return netplan.NewConfiguration(network)
|
||||
}
|
||||
|
||||
func newNetplanNetwork(allNics []*types.SServerNic, bondNics []*types.SServerNic, mainIp string) *netplan.Network {
|
||||
func newNetplanNetwork(allNics []*types.SServerNic, bondNics []*types.SServerNic, mainIp, mainIp6 string) *netplan.Network {
|
||||
network := netplan.NewNetwork()
|
||||
|
||||
nicCnt := len(allNics) - len(bondNics)
|
||||
for _, nic := range allNics {
|
||||
nicConf := getNetplanEthernetConfig(nic, false, mainIp, nicCnt)
|
||||
nicConf := getNetplanEthernetConfig(nic, false, mainIp, mainIp6, nicCnt)
|
||||
if nicConf == nil {
|
||||
continue
|
||||
}
|
||||
@@ -87,7 +88,7 @@ func newNetplanNetwork(allNics []*types.SServerNic, bondNics []*types.SServerNic
|
||||
network.AddEthernet(sn.Name, nicConf)
|
||||
}
|
||||
|
||||
netConf := getNetplanEthernetConfig(bondNic, true, mainIp, nicCnt)
|
||||
netConf := getNetplanEthernetConfig(bondNic, true, mainIp, mainIp6, nicCnt)
|
||||
|
||||
if netConf.Mtu == 0 {
|
||||
netConf.Mtu = defaultMtu
|
||||
@@ -102,7 +103,7 @@ func newNetplanNetwork(allNics []*types.SServerNic, bondNics []*types.SServerNic
|
||||
return network
|
||||
}
|
||||
|
||||
func getNetplanEthernetConfig(nic *types.SServerNic, isBond bool, mainIp string, nicCnt int) *netplan.EthernetConfig {
|
||||
func getNetplanEthernetConfig(nic *types.SServerNic, isBond bool, mainIp, mainIp6 string, nicCnt int) *netplan.EthernetConfig {
|
||||
var nicConf *netplan.EthernetConfig
|
||||
|
||||
if !isBond && (nic.TeamingMaster != nil || nic.TeamingSlaves != nil) {
|
||||
@@ -120,20 +121,27 @@ func getNetplanEthernetConfig(nic *types.SServerNic, isBond bool, mainIp string,
|
||||
gateway6 := ""
|
||||
if len(nic.Ip6) > 0 {
|
||||
addr6 = fmt.Sprintf("%s/%d", nic.Ip6, nic.Masklen6)
|
||||
if nic.Ip == mainIp && len(mainIp) > 0 {
|
||||
if nic.Ip6 == mainIp6 && len(mainIp6) > 0 {
|
||||
gateway6 = nic.Gateway6
|
||||
}
|
||||
}
|
||||
|
||||
var routeArrs = make([][]string, 0)
|
||||
routeArrs = netutils2.AddNicRoutes(routeArrs, nic, mainIp, nicCnt)
|
||||
routeArrs4 := make([]dhcp.SRouteInfo, 0)
|
||||
routeArrs6 := make([]dhcp.SRouteInfo, 0)
|
||||
routeArrs4, routeArrs6 = netutils2.AddNicRoutes(routeArrs4, routeArrs6, nic, mainIp, mainIp6, nicCnt)
|
||||
|
||||
var routes []*netplan.Route
|
||||
|
||||
for _, route := range routeArrs {
|
||||
for _, route := range routeArrs4 {
|
||||
routes = append(routes, &netplan.Route{
|
||||
To: route[0],
|
||||
Via: route[1],
|
||||
To: fmt.Sprintf("%s/%d", route.Prefix, route.PrefixLen),
|
||||
Via: route.Gateway.String(),
|
||||
})
|
||||
}
|
||||
for _, route := range routeArrs6 {
|
||||
routes = append(routes, &netplan.Route{
|
||||
To: fmt.Sprintf("%s/%d", route.Prefix, route.PrefixLen),
|
||||
Via: route.Gateway.String(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ func TestNewNetplanConfig(t *testing.T) {
|
||||
mainIp string
|
||||
nics []*types.SServerNic
|
||||
want *netplan.Configuration
|
||||
|
||||
mainIp6 string
|
||||
}{
|
||||
{
|
||||
mainIp: "10.168.222.175",
|
||||
@@ -254,10 +256,138 @@ 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",
|
||||
Domain: "cloud.local",
|
||||
Ip: "10.168.222.175",
|
||||
Vlan: 1,
|
||||
Driver: "virtio",
|
||||
Masklen: 24,
|
||||
Virtual: false,
|
||||
Manual: true,
|
||||
WireId: "399a06f3-7925-46c1-8b9f-d5a8580a74df",
|
||||
NetId: "22c93412-5882-4de0-8357-45ce647ceada",
|
||||
Mac: "00:24:c7:16:80:f2",
|
||||
BandWidth: 1000,
|
||||
Mtu: 1500,
|
||||
Dns: "8.8.8.8",
|
||||
Ntp: "",
|
||||
Net: "vnet222",
|
||||
Interface: "ens5",
|
||||
Gateway: "10.168.222.1",
|
||||
Ifname: "vnet222-175",
|
||||
Routes: nil,
|
||||
|
||||
LinkUp: true,
|
||||
|
||||
Ip6: "2001:db8::23",
|
||||
Masklen6: 64,
|
||||
Gateway6: "2001:db8::1",
|
||||
},
|
||||
&types.SServerNic{
|
||||
Name: "eth1",
|
||||
Index: 1,
|
||||
Bridge: "br0",
|
||||
Domain: "cloud.local",
|
||||
Ip: "",
|
||||
Vlan: 1,
|
||||
Driver: "virtio",
|
||||
Masklen: 0,
|
||||
Virtual: true,
|
||||
Manual: true,
|
||||
WireId: "399a06f3-7925-46c1-8b9f-d5a8580a74df",
|
||||
NetId: "22c93412-5882-4de0-8357-45ce647ceada",
|
||||
Mac: "00:24:c7:16:80:f3",
|
||||
BandWidth: 1000,
|
||||
Mtu: 1500,
|
||||
Dns: "8.8.8.8",
|
||||
Ntp: "",
|
||||
Net: "vnet222",
|
||||
Interface: "ens5",
|
||||
Gateway: "",
|
||||
Ifname: "vnet222-bpg",
|
||||
Routes: nil,
|
||||
|
||||
LinkUp: true,
|
||||
TeamWith: "00:24:c7:16:80:f2",
|
||||
},
|
||||
},
|
||||
want: &netplan.Configuration{
|
||||
Network: &netplan.Network{
|
||||
Version: 2,
|
||||
Renderer: netplan.NetworkRendererNetworkd,
|
||||
Ethernets: map[string]*netplan.EthernetConfig{
|
||||
"eth0": &netplan.EthernetConfig{
|
||||
MacAddress: "00:24:c7:16:80:f2",
|
||||
Match: &netplan.EthernetConfigMatch{
|
||||
MacAddress: "00:24:c7:16:80:f2",
|
||||
},
|
||||
Mtu: 1500,
|
||||
},
|
||||
"eth1": &netplan.EthernetConfig{
|
||||
MacAddress: "00:24:c7:16:80:f3",
|
||||
Match: &netplan.EthernetConfigMatch{
|
||||
MacAddress: "00:24:c7:16:80:f3",
|
||||
},
|
||||
Mtu: 1500,
|
||||
},
|
||||
},
|
||||
Bonds: map[string]*netplan.Bond{
|
||||
"bond0": &netplan.Bond{
|
||||
EthernetConfig: netplan.EthernetConfig{
|
||||
Addresses: []string{
|
||||
"10.168.222.175/24",
|
||||
"2001:db8::23/64",
|
||||
},
|
||||
MacAddress: "00:24:c7:16:80:f2",
|
||||
Gateway6: "2001:db8::1",
|
||||
Nameservers: &netplan.Nameservers{
|
||||
Search: []string{
|
||||
"cloud.local",
|
||||
},
|
||||
Addresses: []string{
|
||||
"8.8.8.8",
|
||||
},
|
||||
},
|
||||
Mtu: 1500,
|
||||
Routes: []*netplan.Route{
|
||||
{
|
||||
Metric: 0,
|
||||
To: "fd00:ec2::254/128",
|
||||
Via: "::",
|
||||
},
|
||||
{
|
||||
Metric: 0,
|
||||
To: "fe80::a9fe:a9fe/128",
|
||||
Via: "::",
|
||||
},
|
||||
},
|
||||
},
|
||||
Interfaces: []string{
|
||||
"eth0",
|
||||
"eth1",
|
||||
},
|
||||
Parameters: &netplan.BondMode4Params{
|
||||
BondModeBaseParams: &netplan.BondModeBaseParams{
|
||||
Mode: "802.3ad",
|
||||
MiiMonitorInterval: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
allNics, bondNics := convertNicConfigs(c.nics)
|
||||
netplanConfig := NewNetplanConfig(allNics, bondNics, c.mainIp)
|
||||
netplanConfig := NewNetplanConfig(allNics, bondNics, c.mainIp, c.mainIp6)
|
||||
if jsonutils.Marshal(netplanConfig).String() != jsonutils.Marshal(c.want).String() {
|
||||
t.Errorf("nics %d: %s want: %s got: %s", i, jsonutils.Marshal(c.nics), jsonutils.Marshal(c.want).PrettyString(), jsonutils.Marshal(netplanConfig).PrettyString())
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package fsdriver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
|
||||
@@ -85,7 +87,7 @@ func (r *sSuseLikeRootFs) enableBondingModule(rootFs IDiskPartition, bondNics []
|
||||
return rootFs.FilePutContents("/etc/modprobe.d/bonding.conf", content.String(), false, false)
|
||||
}
|
||||
|
||||
func (r *sSuseLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scriptPath, mainIp string, nicCnt int, nicDesc *types.SServerNic) error {
|
||||
func (r *sSuseLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scriptPath, mainIp, mainIp6 string, nicCnt int, nicDesc *types.SServerNic) error {
|
||||
var cmds strings.Builder
|
||||
var ifname = fmt.Sprintf("%s.%d", nicDesc.Name, nicDesc.Vlan)
|
||||
cmds.WriteString("STARTMODE=auto\n")
|
||||
@@ -104,26 +106,37 @@ func (r *sSuseLikeRootFs) deployVlanNetworkingScripts(rootFs IDiskPartition, scr
|
||||
cmds.WriteString(fmt.Sprintf("VLAN_ID=%d\n", nicDesc.Vlan))
|
||||
cmds.WriteString(fmt.Sprintf("ETHERDEVICE=%s\n", nicDesc.Name))
|
||||
|
||||
var routes = make([][]string, 0)
|
||||
var routes4 = make([]dhcp.SRouteInfo, 0)
|
||||
var routes6 = make([]dhcp.SRouteInfo, 0)
|
||||
var dnsSrv []string
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
|
||||
routes = append(routes, []string{
|
||||
"default",
|
||||
nicDesc.Gateway,
|
||||
routes4 = append(routes4, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicDesc.Gateway),
|
||||
})
|
||||
}
|
||||
if len(nicDesc.Gateway6) > 0 && nicDesc.Ip == mainIp {
|
||||
routes = append(routes, []string{
|
||||
"default",
|
||||
nicDesc.Gateway6,
|
||||
if len(nicDesc.Gateway6) > 0 && nicDesc.Ip6 == mainIp6 {
|
||||
routes6 = append(routes6, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicDesc.Gateway6),
|
||||
})
|
||||
}
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes {
|
||||
rtbl.WriteString(r[0])
|
||||
for _, r := range routes4 {
|
||||
rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
|
||||
rtbl.WriteString(" ")
|
||||
rtbl.WriteString(r[1])
|
||||
rtbl.WriteString(r.Gateway.String())
|
||||
rtbl.WriteString(" - ")
|
||||
rtbl.WriteString(nicDesc.Name)
|
||||
rtbl.WriteString("\n")
|
||||
}
|
||||
for _, r := range routes6 {
|
||||
rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
|
||||
rtbl.WriteString(" ")
|
||||
rtbl.WriteString(r.Gateway.String())
|
||||
rtbl.WriteString(" - ")
|
||||
rtbl.WriteString(nicDesc.Name)
|
||||
rtbl.WriteString("\n")
|
||||
@@ -169,11 +182,18 @@ func (r *sSuseLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics []
|
||||
nicCnt := len(allNics) - len(bondNics)
|
||||
|
||||
var dnsSrv []string
|
||||
|
||||
mainNic := getMainNic(allNics)
|
||||
var mainIp string
|
||||
if mainNic != nil {
|
||||
mainIp = mainNic.Ip
|
||||
}
|
||||
mainNic6 := getMainNic6(allNics)
|
||||
var mainIp6 string
|
||||
if mainNic6 != nil {
|
||||
mainIp6 = mainNic6.Ip6
|
||||
}
|
||||
|
||||
for i := range allNics {
|
||||
nicDesc := allNics[i]
|
||||
var cmds strings.Builder
|
||||
@@ -212,25 +232,36 @@ func (r *sSuseLikeRootFs) deployNetworkingScripts(rootFs IDiskPartition, nics []
|
||||
cmds.WriteString(fmt.Sprintf("IPADDR_V6=%s/%d\n", nicDesc.Ip6, nicDesc.Masklen6))
|
||||
}
|
||||
|
||||
var routes = make([][]string, 0)
|
||||
routes = netutils2.AddNicRoutes(routes, nicDesc, mainIp, nicCnt)
|
||||
var routes4 = make([]dhcp.SRouteInfo, 0)
|
||||
var routes6 = make([]dhcp.SRouteInfo, 0)
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, nicDesc, mainIp, mainIp6, nicCnt)
|
||||
if len(nicDesc.Gateway) > 0 && nicDesc.Ip == mainIp {
|
||||
routes = append(routes, []string{
|
||||
"default",
|
||||
nicDesc.Gateway,
|
||||
routes4 = append(routes4, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicDesc.Gateway),
|
||||
})
|
||||
}
|
||||
if len(nicDesc.Gateway6) > 0 && nicDesc.Ip == mainIp {
|
||||
routes = append(routes, []string{
|
||||
"default",
|
||||
nicDesc.Gateway6,
|
||||
if len(nicDesc.Gateway6) > 0 && nicDesc.Ip6 == mainIp6 {
|
||||
routes6 = append(routes6, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicDesc.Gateway6),
|
||||
})
|
||||
}
|
||||
var rtbl strings.Builder
|
||||
for _, r := range routes {
|
||||
rtbl.WriteString(r[0])
|
||||
for _, r := range routes4 {
|
||||
rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
|
||||
rtbl.WriteString(" ")
|
||||
rtbl.WriteString(r[1])
|
||||
rtbl.WriteString(r.Gateway.String())
|
||||
rtbl.WriteString(" - ")
|
||||
rtbl.WriteString(nicDesc.Name)
|
||||
rtbl.WriteString("\n")
|
||||
}
|
||||
for _, r := range routes6 {
|
||||
rtbl.WriteString(fmt.Sprintf("%s/%d", r.Prefix, r.PrefixLen))
|
||||
rtbl.WriteString(" ")
|
||||
rtbl.WriteString(r.Gateway.String())
|
||||
rtbl.WriteString(" - ")
|
||||
rtbl.WriteString(nicDesc.Name)
|
||||
rtbl.WriteString("\n")
|
||||
|
||||
@@ -31,6 +31,7 @@ import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
@@ -288,6 +289,10 @@ func (w *SWindowsRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*
|
||||
if mainNic != nil {
|
||||
mainIp = mainNic.Ip
|
||||
}
|
||||
mainIp6 := ""
|
||||
if mainNic != nil {
|
||||
mainIp6 = mainNic.Ip6
|
||||
}
|
||||
bootScript := strings.Join([]string{
|
||||
`set NETCFG_SCRIPT=%SystemRoot%\netcfg.bat`,
|
||||
`if exist %NETCFG_SCRIPT% (`,
|
||||
@@ -322,15 +327,19 @@ func (w *SWindowsRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*
|
||||
if len(snic.Ip6) > 0 {
|
||||
cfg := fmt.Sprintf(` netsh interface ipv6 add address "%%%%b" %s/%d store=persistent`, snic.Ip6, snic.Masklen6)
|
||||
lines = append(lines, cfg)
|
||||
if len(snic.Gateway) > 0 && snic.Ip == mainIp {
|
||||
if len(snic.Gateway6) > 0 && snic.Ip6 == mainIp6 {
|
||||
cfg := fmt.Sprintf(` netsh interface ipv6 add route ::/0 "%%%%b" %s`, snic.Gateway6)
|
||||
lines = append(lines, cfg)
|
||||
}
|
||||
}
|
||||
routes := [][]string{}
|
||||
routes = netutils2.AddNicRoutes(routes, snic, mainIp, len(nics))
|
||||
for _, r := range routes {
|
||||
lines = append(lines, fmt.Sprintf(` netsh interface ip add route %s "%%%%b" %s`, r[0], r[1]))
|
||||
routes4 := []dhcp.SRouteInfo{}
|
||||
routes6 := []dhcp.SRouteInfo{}
|
||||
routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, snic, mainIp, mainIp6, len(nics))
|
||||
for _, r := range routes4 {
|
||||
lines = append(lines, fmt.Sprintf(` netsh interface ip add route %s/%d %s "%%%%b"`, r.Prefix, r.PrefixLen, r.Gateway.String()))
|
||||
}
|
||||
for _, r := range routes6 {
|
||||
lines = append(lines, fmt.Sprintf(` netsh interface ipv6 add route %s/%d %s "%%%%b"`, r.Prefix, r.PrefixLen, r.Gateway.String()))
|
||||
}
|
||||
dnslist := netutils2.GetNicDns(snic)
|
||||
if len(dnslist) > 0 {
|
||||
|
||||
@@ -70,9 +70,9 @@ func (r *SDHCP6Relay) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *
|
||||
return pkg, nil, err
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) ServeRA(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, error) {
|
||||
func (r *SDHCP6Relay) ServeRA(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, net.IP, net.HardwareAddr, error) {
|
||||
pkg, err := r.serveDHCPInternal(pkt, addr)
|
||||
return pkg, err
|
||||
return pkg, nil, nil, err
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr) (dhcp.Packet, error) {
|
||||
|
||||
@@ -20,7 +20,9 @@ import (
|
||||
"time"
|
||||
|
||||
"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"
|
||||
@@ -42,7 +44,7 @@ type SGuestDHCPServer struct {
|
||||
relay *SDHCPRelay
|
||||
conn *dhcp.Conn
|
||||
|
||||
iface string
|
||||
ifaceDev *netutils2.SNetInterface
|
||||
}
|
||||
|
||||
type SDHCPRelayUpstream struct {
|
||||
@@ -56,19 +58,25 @@ func NewGuestDHCPServer(iface string, port int, relay *SDHCPRelayUpstream) (*SGu
|
||||
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, err
|
||||
return nil, errors.Wrap(err, "dhcp.NewDHCPServer2")
|
||||
}
|
||||
|
||||
if relay != nil {
|
||||
guestdhcp.relay, err = NewDHCPRelay(guestdhcp.conn, relay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "NewDHCPRelay")
|
||||
}
|
||||
}
|
||||
|
||||
guestdhcp.iface = iface
|
||||
return guestdhcp, nil
|
||||
}
|
||||
|
||||
@@ -143,11 +151,31 @@ func GetMainNic(nics []*desc.SGuestNetwork) *desc.SGuestNetwork {
|
||||
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 {
|
||||
@@ -156,6 +184,9 @@ func getGuestConfig(
|
||||
}
|
||||
|
||||
var conf = new(dhcp.ResponseConfig)
|
||||
|
||||
conf.InterfaceMac = serverMac
|
||||
|
||||
nicIp := nicdesc.Ip
|
||||
v4Ip, _ := netutils.NewIPV4Addr(nicIp)
|
||||
conf.ClientIP = net.ParseIP(nicdesc.Ip)
|
||||
@@ -174,46 +205,87 @@ func getGuestConfig(
|
||||
|
||||
if len(nicdesc.Ip6) > 0 {
|
||||
// ipv6
|
||||
conf.Gateway6 = net.ParseIP(nicdesc.Gateway6)
|
||||
conf.PrefixLen6 = uint8(nicdesc.Masklen6)
|
||||
conf.ClientIP6 = net.ParseIP(nicdesc.Ip6)
|
||||
}
|
||||
|
||||
// get main ip
|
||||
guestNics := guestDesc.Nics
|
||||
manNic := GetMainNic(guestNics)
|
||||
mainNic := GetMainNic(guestNics)
|
||||
var mainIp string
|
||||
if manNic != nil {
|
||||
mainIp = manNic.Ip
|
||||
if mainNic != nil {
|
||||
mainIp = mainNic.Ip
|
||||
}
|
||||
mainNic6 := GetMainNic6(guestNics)
|
||||
var mainIp6 string
|
||||
if mainNic6 != nil {
|
||||
mainIp6 = mainNic6.Ip6
|
||||
}
|
||||
|
||||
var route = [][]string{}
|
||||
route4 := make([]dhcp.SRouteInfo, 0)
|
||||
route6 := make([]dhcp.SRouteInfo, 0)
|
||||
if nicdesc.IsDefault {
|
||||
conf.Gateway = net.ParseIP(nicdesc.Gateway)
|
||||
|
||||
osName := guestDesc.OsName
|
||||
if len(osName) == 0 {
|
||||
osName = "Linux"
|
||||
}
|
||||
if !strings.HasPrefix(strings.ToLower(osName), "win") {
|
||||
route = append(route, []string{"0.0.0.0/0", nicdesc.Gateway})
|
||||
|
||||
if nicdesc.Gateway != "" {
|
||||
conf.Gateway = net.ParseIP(nicdesc.Gateway)
|
||||
|
||||
if !strings.HasPrefix(strings.ToLower(osName), "win") {
|
||||
route4 = append(route4, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("0.0.0.0"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicdesc.Gateway),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(nicdesc.Gateway6) > 0 {
|
||||
conf.Gateway6 = net.ParseIP(nicdesc.Gateway6)
|
||||
conf.PrefixLen6 = uint8(nicdesc.Masklen6)
|
||||
route6 = append(route6, dhcp.SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP(nicdesc.Gateway6),
|
||||
})
|
||||
}
|
||||
route = append(route, []string{"169.254.169.254/32", "0.0.0.0"})
|
||||
}
|
||||
route = netutils2.AddNicRoutes(route, nicdesc, mainIp, len(guestNics))
|
||||
conf.Routes = route
|
||||
route4, route6 = netutils2.AddNicRoutes(route4, route6, nicdesc, mainIp, mainIp6, len(guestNics))
|
||||
|
||||
conf.Routes = route4
|
||||
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, ",") {
|
||||
conf.DNSServers = append(conf.DNSServers, net.ParseIP(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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(nicdesc.Ntp) > 0 {
|
||||
conf.NTPServers = make([]net.IP, 0)
|
||||
conf.NTPServers6 = make([]net.IP, 0)
|
||||
for _, ntp := range strings.Split(nicdesc.Ntp, ",") {
|
||||
conf.NTPServers = append(conf.NTPServers, net.ParseIP(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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,12 +309,12 @@ func (s *SGuestDHCPServer) getConfig(pkt dhcp.Packet) *dhcp.ResponseConfig {
|
||||
ip, port = "", ""
|
||||
isCandidate = false
|
||||
)
|
||||
guestDesc, guestNic := guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.iface, isCandidate)
|
||||
guestDesc, guestNic := guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.ifaceDev.String(), isCandidate)
|
||||
if guestNic == nil {
|
||||
guestDesc, guestNic = guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.iface, !isCandidate)
|
||||
guestDesc, guestNic = guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.ifaceDev.String(), !isCandidate)
|
||||
}
|
||||
if guestNic != nil && !guestNic.Virtual {
|
||||
return getGuestConfig(guestDesc, guestNic)
|
||||
if guestNic != nil && !guestNic.Virtual && len(guestNic.Ip6) > 0 {
|
||||
return getGuestConfig(guestDesc, guestNic, s.ifaceDev.GetHardwareAddr())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ import (
|
||||
"net"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
guestman "yunion.io/x/onecloud/pkg/hostman/guestman/types"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,7 +36,7 @@ type SGuestDHCP6Server struct {
|
||||
relay *SDHCP6Relay
|
||||
conn *dhcp.Conn
|
||||
|
||||
iface string
|
||||
ifaceDev *netutils2.SNetInterface
|
||||
}
|
||||
|
||||
func NewGuestDHCP6Server(iface string, port int, relay *SDHCPRelayUpstream) (*SGuestDHCP6Server, error) {
|
||||
@@ -43,19 +45,25 @@ func NewGuestDHCP6Server(iface string, port int, relay *SDHCPRelayUpstream) (*SG
|
||||
guestdhcp = new(SGuestDHCP6Server)
|
||||
)
|
||||
|
||||
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.NewDHCP6Server2(iface, DEFAULT_DHCP6_SERVER_PORT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "dhcp.NewDHCP6Server2")
|
||||
}
|
||||
|
||||
if relay != nil {
|
||||
guestdhcp.relay, err = NewDHCP6Relay(guestdhcp.conn, relay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "NewDHCP6Relay")
|
||||
}
|
||||
}
|
||||
|
||||
guestdhcp.iface = iface
|
||||
return guestdhcp, nil
|
||||
}
|
||||
|
||||
@@ -90,12 +98,12 @@ func (s *SGuestDHCP6Server) getConfig(cliMac net.HardwareAddr, _ dhcp.Packet) *d
|
||||
ip, port = "", ""
|
||||
isCandidate = false
|
||||
)
|
||||
guestDesc, guestNic := guestman.GuestDescGetter.GetGuestNicDesc(cliMac.String(), ip, port, s.iface, isCandidate)
|
||||
guestDesc, guestNic := guestman.GuestDescGetter.GetGuestNicDesc(cliMac.String(), ip, port, s.ifaceDev.String(), isCandidate)
|
||||
if guestNic == nil {
|
||||
guestDesc, guestNic = guestman.GuestDescGetter.GetGuestNicDesc(cliMac.String(), ip, port, s.iface, !isCandidate)
|
||||
guestDesc, guestNic = guestman.GuestDescGetter.GetGuestNicDesc(cliMac.String(), ip, port, s.ifaceDev.String(), !isCandidate)
|
||||
}
|
||||
if guestNic != nil && !guestNic.Virtual && len(guestNic.Ip6) > 0 {
|
||||
return getGuestConfig(guestDesc, guestNic)
|
||||
return getGuestConfig(guestDesc, guestNic, s.ifaceDev.GetHardwareAddr())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -105,20 +113,21 @@ func (s *SGuestDHCP6Server) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr,
|
||||
return pkg, nil, err
|
||||
}
|
||||
|
||||
func (s *SGuestDHCP6Server) ServeRA(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, error) {
|
||||
var conf = s.getConfig(cliMac, pkt)
|
||||
func (s *SGuestDHCP6Server) ServeRA(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, net.IP, net.HardwareAddr, error) {
|
||||
log.Infof("SGuestDHCP6Server ServeRA from %s", cliMac.String())
|
||||
var conf = s.getConfig(cliMac, nil)
|
||||
if conf != nil {
|
||||
return dhcp.MakeRouterAdverPacket(conf.Gateway6, conf.PrefixLen6, uint32(conf.MTU))
|
||||
return dhcp.MakeRouterAdverPacket(conf.Gateway6, conf.PrefixLen6, conf.Routes6, uint32(conf.MTU))
|
||||
}
|
||||
return nil, nil
|
||||
return nil, nil, nil, nil
|
||||
}
|
||||
|
||||
func (s *SGuestDHCP6Server) serveDHCPInternal(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, error) {
|
||||
var conf = s.getConfig(cliMac, pkt)
|
||||
if conf != nil {
|
||||
log.Infof("Make DHCPv6 Reply %s TO %s", conf.ClientIP6, pkt.CHAddr())
|
||||
log.Infof("Make DHCPv6 Reply %s TO %s %s", conf.ClientIP6, cliMac.String(), addr.String())
|
||||
// Guest request ip
|
||||
return dhcp.MakeReplyPacket(pkt, conf)
|
||||
return dhcp.MakeDHCP6Reply(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)
|
||||
|
||||
@@ -73,6 +73,7 @@ type conn interface {
|
||||
Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error
|
||||
Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error)
|
||||
Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error
|
||||
SendICMP6(b []byte, srcIp net.IP, srcMac, destMac net.HardwareAddr) error
|
||||
Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error)
|
||||
SetReadDeadline(t time.Time) error
|
||||
SetWriteDeadline(t time.Time) error
|
||||
@@ -208,6 +209,16 @@ func (c *Conn) SendDHCP(pkt Packet, addr *net.UDPAddr, mac net.HardwareAddr) err
|
||||
return c.conn.Send(b, addr, mac)
|
||||
}
|
||||
|
||||
func (c *Conn) SendDHCP6(pkt Packet, addr *net.UDPAddr, mac net.HardwareAddr) error {
|
||||
b := pkt.Marshal()
|
||||
return c.conn.Send6(b, addr, mac)
|
||||
}
|
||||
|
||||
func (c *Conn) SendICMP6(pkt Packet, srcIp net.IP, srcmac, dstmac net.HardwareAddr) error {
|
||||
b := pkt.Marshal()
|
||||
return c.conn.SendICMP6(b, srcIp, srcmac, dstmac)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls. If the
|
||||
// deadline is reached, Read will fail with a timeout (see net.Error)
|
||||
// instead of blocking. A zero value for t means Read will not time
|
||||
|
||||
@@ -70,11 +70,11 @@ func interfaceToIPv6Addr(ifi *net.Interface) (net.IP, error) {
|
||||
for _, ifa := range ifat {
|
||||
switch v := ifa.(type) {
|
||||
case *net.IPAddr:
|
||||
if len(v.IP) == net.IPv6len {
|
||||
if v.IP.To4() == nil && v.IP.To16() != nil {
|
||||
return v.IP, nil
|
||||
}
|
||||
case *net.IPNet:
|
||||
if len(v.IP) == net.IPv6len {
|
||||
if v.IP.To4() == nil && v.IP.To16() != nil {
|
||||
return v.IP, nil
|
||||
}
|
||||
}
|
||||
@@ -146,3 +146,7 @@ func (s *socketConn) Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr
|
||||
}
|
||||
return syscall.Sendto(s.sock, b, 0, destAddr)
|
||||
}
|
||||
|
||||
func (s *socketConn) SendICMP6(b []byte, srcIp net.IP, srcMac, destMac net.HardwareAddr) error {
|
||||
return errors.Wrap(errors.ErrNotImplemented, "SendICMP6 not implemented")
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
|
||||
icmpLayer := p.Layer(layers.LayerTypeICMPv6)
|
||||
if icmpLayer != nil {
|
||||
log.Infof("rawSocketConn Recv6 icmpLayer %s", icmpLayer.LayerType())
|
||||
raLayer := p.Layer(layers.LayerTypeICMPv6RouterSolicitation)
|
||||
if raLayer != nil {
|
||||
// icmp6, ra solitation
|
||||
@@ -143,14 +144,56 @@ func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) SendICMP6(b []byte, srcIP net.IP, srcMac, destMac net.HardwareAddr) error {
|
||||
var icmpRouterAdvMsg = new(layers.ICMPv6RouterAdvertisement)
|
||||
if err := icmpRouterAdvMsg.DecodeFromBytes(b, gopacket.NilDecodeFeedback); err != nil {
|
||||
return errors.Wrap(err, "Decode icmp router advertisement bytes error")
|
||||
}
|
||||
|
||||
var eth = &layers.Ethernet{
|
||||
EthernetType: layers.EthernetTypeIPv6,
|
||||
SrcMAC: s.iface.HardwareAddr,
|
||||
DstMAC: destMac,
|
||||
}
|
||||
|
||||
dstIP := net.ParseIP("ff02::1")
|
||||
|
||||
var ip = &layers.IPv6{
|
||||
Version: 6,
|
||||
HopLimit: 64,
|
||||
SrcIP: srcIP,
|
||||
DstIP: dstIP,
|
||||
NextHeader: layers.IPProtocolICMPv6,
|
||||
}
|
||||
|
||||
var icmp6 = &layers.ICMPv6{
|
||||
TypeCode: layers.CreateICMPv6TypeCode(layers.ICMPv6TypeRouterAdvertisement, 0),
|
||||
}
|
||||
icmp6.SetNetworkLayerForChecksum(ip)
|
||||
|
||||
var (
|
||||
buf = gopacket.NewSerializeBuffer()
|
||||
opts = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
|
||||
)
|
||||
if err := gopacket.SerializeLayers(buf, opts, eth, ip, icmp6, icmpRouterAdvMsg); err != nil {
|
||||
return errors.Wrap(err, "SerializeLayers error")
|
||||
}
|
||||
|
||||
// s.conn.SetWriteDeadline(time.Now().Add(DefaultWriteTimeout)) // 2 second
|
||||
if _, err := s.conn.WriteTo(buf.Bytes(), &packet.Addr{HardwareAddr: destMac}); err != nil {
|
||||
return errors.Wrap(err, "Send icmp packet error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error {
|
||||
var dhcp = new(layers.DHCPv4)
|
||||
var dhcp = new(layers.DHCPv6)
|
||||
if err := dhcp.DecodeFromBytes(b, gopacket.NilDecodeFeedback); err != nil {
|
||||
return errors.Wrap(err, "Decode dhcp bytes error")
|
||||
}
|
||||
|
||||
var eth = &layers.Ethernet{
|
||||
EthernetType: layers.EthernetTypeIPv4,
|
||||
EthernetType: layers.EthernetTypeIPv6,
|
||||
SrcMAC: s.iface.HardwareAddr,
|
||||
DstMAC: destMac,
|
||||
}
|
||||
|
||||
+42
-12
@@ -18,11 +18,11 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,6 +34,8 @@ const (
|
||||
|
||||
// http://www.networksorcery.com/enp/rfc/rfc2132.txt
|
||||
type ResponseConfig struct {
|
||||
InterfaceMac net.HardwareAddr
|
||||
|
||||
OsName string
|
||||
ServerIP net.IP // OptServerIdentifier 54
|
||||
ClientIP net.IP
|
||||
@@ -45,13 +47,16 @@ type ResponseConfig struct {
|
||||
Hostname string // OptHostname 12
|
||||
SubnetMask net.IP // OptSubnetMask 1
|
||||
DNSServers []net.IP // OptDNSServers
|
||||
Routes [][]string // TODO: 249 for windows, 121 for linux
|
||||
Routes []SRouteInfo // TODO: 249 for windows, 121 for linux
|
||||
NTPServers []net.IP // OptNTPServers 42
|
||||
MTU uint16 // OptMTU 26
|
||||
|
||||
ClientIP6 net.IP
|
||||
Gateway6 net.IP
|
||||
PrefixLen6 uint8
|
||||
ClientIP6 net.IP
|
||||
Gateway6 net.IP
|
||||
PrefixLen6 uint8
|
||||
DNSServers6 []net.IP
|
||||
NTPServers6 []net.IP
|
||||
Routes6 []SRouteInfo
|
||||
|
||||
// Relay Info https://datatracker.ietf.org/doc/html/rfc3046
|
||||
RelayInfo []byte
|
||||
@@ -90,14 +95,40 @@ func GetOptTime(d time.Duration) []byte {
|
||||
return timeBytes
|
||||
}
|
||||
|
||||
func getClasslessRoutePack(route []string) []byte {
|
||||
var snet, gw = route[0], route[1]
|
||||
tmp := strings.Split(snet, "/")
|
||||
netaddr := net.ParseIP(tmp[0])
|
||||
type SRouteInfo struct {
|
||||
Prefix net.IP
|
||||
PrefixLen uint8
|
||||
Gateway net.IP
|
||||
}
|
||||
|
||||
func (r SRouteInfo) String() string {
|
||||
return fmt.Sprintf("%s/%d via %s", r.Prefix.String(), r.PrefixLen, r.Gateway.String())
|
||||
}
|
||||
|
||||
func ParseRouteInfo(route []string) (*SRouteInfo, error) {
|
||||
if len(route) < 2 {
|
||||
return nil, errors.Wrapf(errors.ErrInvalidStatus, "invalid route %#v", route)
|
||||
}
|
||||
_, prefixLen, err := net.ParseCIDR(route[0])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "net.ParseCIDR %s", route[0])
|
||||
}
|
||||
ones, _ := prefixLen.Mask.Size()
|
||||
return &SRouteInfo{
|
||||
Prefix: prefixLen.IP,
|
||||
PrefixLen: uint8(ones),
|
||||
Gateway: net.ParseIP(route[1]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getClasslessRoutePack(route SRouteInfo) []byte {
|
||||
// var snet, gw = route[0], route[1]
|
||||
// tmp := strings.Split(snet, "/")
|
||||
netaddr := route.Prefix
|
||||
if netaddr != nil {
|
||||
netaddr = netaddr.To4()
|
||||
}
|
||||
masklen, _ := strconv.Atoi(tmp[1])
|
||||
masklen := route.PrefixLen
|
||||
netlen := masklen / 8
|
||||
if masklen%8 > 0 {
|
||||
netlen += 1
|
||||
@@ -105,11 +136,10 @@ func getClasslessRoutePack(route []string) []byte {
|
||||
if netlen < 4 {
|
||||
netaddr = netaddr[0:netlen]
|
||||
}
|
||||
gwaddr := net.ParseIP(gw)
|
||||
gwaddr := route.Gateway
|
||||
if gwaddr != nil {
|
||||
gwaddr = gwaddr.To4()
|
||||
}
|
||||
|
||||
res := []byte{byte(masklen)}
|
||||
res = append(res, []byte(netaddr)...)
|
||||
return append(res, []byte(gwaddr)...)
|
||||
|
||||
@@ -16,6 +16,7 @@ package dhcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -60,9 +61,69 @@ func TestGetClasslessRoutePack(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := getClasslessRoutePack([]string{c.net, c.gw})
|
||||
routeInfo, err := ParseRouteInfo([]string{c.net, c.gw})
|
||||
if err != nil {
|
||||
t.Errorf("parse route %s error: %v", c.net, err)
|
||||
continue
|
||||
}
|
||||
got := getClasslessRoutePack(*routeInfo)
|
||||
if err := compareBytes(c.want, got); err != nil {
|
||||
t.Errorf("net: %s gw: %s want: %#v got: %#v", c.net, c.gw, c.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRouteInfo(t *testing.T) {
|
||||
cases := []struct {
|
||||
net string
|
||||
gw string
|
||||
want *SRouteInfo
|
||||
}{
|
||||
{
|
||||
net: "10.0.0.0/8",
|
||||
gw: "10.168.120.1",
|
||||
want: &SRouteInfo{
|
||||
Prefix: net.ParseIP("10.0.0.0"),
|
||||
PrefixLen: 8,
|
||||
Gateway: net.ParseIP("10.168.120.1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "::/0",
|
||||
gw: "3ffe:3200:fe::1",
|
||||
want: &SRouteInfo{
|
||||
Prefix: net.ParseIP("::"),
|
||||
PrefixLen: 0,
|
||||
Gateway: net.ParseIP("3ffe:3200:fe::1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "fd00:ec2::254/128",
|
||||
gw: "::",
|
||||
want: &SRouteInfo{
|
||||
Prefix: net.ParseIP("fd00:ec2::254"),
|
||||
PrefixLen: 128,
|
||||
Gateway: net.ParseIP("::"),
|
||||
},
|
||||
},
|
||||
{
|
||||
net: "fe80::a9fe:a9fe/128",
|
||||
gw: "::",
|
||||
want: &SRouteInfo{
|
||||
Prefix: net.ParseIP("fe80::a9fe:a9fe"),
|
||||
PrefixLen: 128,
|
||||
Gateway: net.ParseIP("::"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
routeInfo, err := ParseRouteInfo([]string{c.net, c.gw})
|
||||
if err != nil {
|
||||
t.Errorf("parse route %s error: %v", c.net, err)
|
||||
continue
|
||||
}
|
||||
if routeInfo.String() != c.want.String() {
|
||||
t.Errorf("parse route expect %s got: %s", c.want.String(), routeInfo.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ type DHCPHandler interface {
|
||||
type DHCP6Handler interface {
|
||||
DHCPHandler
|
||||
|
||||
ServeRA(pkt Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (Packet, error)
|
||||
ServeRA(pkt Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (Packet, net.IP, net.HardwareAddr, error)
|
||||
}
|
||||
|
||||
+290
-32
@@ -16,15 +16,26 @@ package dhcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
)
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.4
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Reserved |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| MTU |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpV6OptMtu struct {
|
||||
MTU uint32
|
||||
}
|
||||
@@ -42,6 +53,7 @@ func NewIcmpV6OptMtu(mtu uint32) icmpV6OptMtu {
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.2
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
@@ -68,7 +80,7 @@ type icmpv6OptPrefixInfo struct {
|
||||
ValidLifetime uint32
|
||||
PreferredLifetime uint32
|
||||
Reserved2 uint32
|
||||
Prefix [16]byte
|
||||
Prefix []byte
|
||||
}
|
||||
|
||||
func (opt icmpv6OptPrefixInfo) Bytes() []byte {
|
||||
@@ -83,52 +95,126 @@ func (opt icmpv6OptPrefixInfo) Bytes() []byte {
|
||||
}
|
||||
|
||||
func NewIcmpv6OptPrefixInfo(gw net.IP, preflen uint8) icmpv6OptPrefixInfo {
|
||||
_, ipnet, _ := net.ParseCIDR(fmt.Sprintf("%s/%d", gw.String(), preflen))
|
||||
return icmpv6OptPrefixInfo{
|
||||
PrefixLen: preflen,
|
||||
Flag: 0x80,
|
||||
ValidLifetime: 0xffffffff,
|
||||
PreferredLifetime: 0xffffffff,
|
||||
Reserved2: 0,
|
||||
Prefix: [16]byte(gw),
|
||||
Prefix: ipnet.IP,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4861#section-4.6.1
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Link-Layer Address ...
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpv6OptSourceTargetAddress struct {
|
||||
Mac netutils.SMacAddr
|
||||
Mac net.HardwareAddr
|
||||
}
|
||||
|
||||
func (opt icmpv6OptSourceTargetAddress) Bytes() []byte {
|
||||
return opt.Mac[:]
|
||||
return opt.Mac[0:6]
|
||||
}
|
||||
|
||||
func NewIcmpv6OptSourceTargetAddress(macAddr string) icmpv6OptSourceTargetAddress {
|
||||
mac, _ := netutils.ParseMac(macAddr)
|
||||
func NewIcmpv6OptSourceTargetAddress(macAddr net.HardwareAddr) icmpv6OptSourceTargetAddress {
|
||||
return icmpv6OptSourceTargetAddress{
|
||||
Mac: mac,
|
||||
Mac: macAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func MakeRouterAdverPacket(gwIP net.IP, preflen uint8, mtu uint32) (Packet, error) {
|
||||
/*
|
||||
https://datatracker.ietf.org/doc/html/rfc4191#section-2.3
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Type | Length | Prefix Length |Resvd|Prf|Resvd|
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Route Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Prefix (Variable Length) |
|
||||
. .
|
||||
. .
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
type icmpv6OptRouteInfo struct {
|
||||
PrefixLen uint8
|
||||
Reserved1 uint8
|
||||
RouteLifetime uint32
|
||||
Prefix []byte
|
||||
}
|
||||
|
||||
func (opt icmpv6OptRouteInfo) Bytes() []byte {
|
||||
buf := make([]byte, 6)
|
||||
buf[0] = opt.PrefixLen
|
||||
buf[1] = opt.Reserved1
|
||||
binary.BigEndian.PutUint32(buf[2:6], opt.RouteLifetime)
|
||||
buf = append(buf, opt.Prefix...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func NewIcmpv6OptRouteInfo(routeLifetime uint32, prefix []byte, prefixLen uint8) icmpv6OptRouteInfo {
|
||||
if prefixLen <= 0 {
|
||||
prefix = prefix[0:0]
|
||||
} else if prefixLen <= 64 {
|
||||
prefix = prefix[0:8]
|
||||
} else {
|
||||
prefix = prefix[0:16]
|
||||
}
|
||||
return icmpv6OptRouteInfo{
|
||||
PrefixLen: prefixLen,
|
||||
Reserved1: 0,
|
||||
RouteLifetime: routeLifetime,
|
||||
Prefix: prefix,
|
||||
}
|
||||
}
|
||||
|
||||
func MakeRouterAdverPacket(gwIP net.IP, prefixLen uint8, routes6 []SRouteInfo, mtu uint32) (Packet, net.IP, net.HardwareAddr, error) {
|
||||
pkt := layers.ICMPv6RouterAdvertisement{}
|
||||
pkt.Flags = 0x80 // M=1, O=0 stateful DHCPv6
|
||||
// https://datatracker.ietf.org/doc/html/rfc4861#section-4.2
|
||||
// https://datatracker.ietf.org/doc/html/rfc4191
|
||||
pkt.Flags = 0xc0 // M=1, O=1, stateful DHCPv6, pref=00
|
||||
pkt.HopLimit = 64
|
||||
pkt.RouterLifetime = 9000
|
||||
pkt.ReachableTime = 0
|
||||
pkt.RetransTimer = 0
|
||||
|
||||
// gwMac, _ := net.ParseMAC("14:09:dc:cf:16:d5")
|
||||
|
||||
pkt.Options = layers.ICMPv6Options{
|
||||
/*layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptSourceAddress,
|
||||
Data: NewIcmpv6OptSourceTargetAddress(gwMac).Bytes(),
|
||||
},*/
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptMTU,
|
||||
Data: NewIcmpV6OptMtu(mtu).Bytes(),
|
||||
},
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptPrefixInfo,
|
||||
Data: NewIcmpv6OptPrefixInfo(gwIP, preflen).Bytes(),
|
||||
Data: NewIcmpv6OptPrefixInfo(gwIP, prefixLen).Bytes(),
|
||||
},
|
||||
}
|
||||
for i := range routes6 {
|
||||
rt := routes6[i]
|
||||
pkt.Options = append(pkt.Options, layers.ICMPv6Option{
|
||||
Type: 24,
|
||||
Data: NewIcmpv6OptRouteInfo(9000, rt.Prefix.To16(), rt.PrefixLen).Bytes(),
|
||||
})
|
||||
}
|
||||
|
||||
sbf := gopacket.NewSerializeBuffer()
|
||||
err := pkt.SerializeTo(sbf, gopacket.SerializeOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SerializeTo")
|
||||
return nil, nil, nil, errors.Wrap(err, "SerializeTo")
|
||||
}
|
||||
return sbf.Bytes(), nil
|
||||
return sbf.Bytes(), gwIP, nil, nil
|
||||
}
|
||||
|
||||
// DHCPv6 https://datatracker.ietf.org/doc/html/rfc8415
|
||||
@@ -212,6 +298,17 @@ const (
|
||||
DHCPV6_OPTION_INFORMATION_REFRESH_TIME OptionCode6 = 32
|
||||
DHCPV6_OPTION_SOL_MAX_RT OptionCode6 = 82
|
||||
DHCPV6_OPTION_INF_MAX_RT OptionCode6 = 83
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc3646
|
||||
OPTION_DNS_SERVERS OptionCode6 = 23
|
||||
OPTION_DOMAIN_LIST OptionCode6 = 24
|
||||
// https://www.rfc-editor.org/rfc/rfc4075
|
||||
OPTION_SNTP_SERVERS OptionCode6 = 31
|
||||
//https://www.rfc-editor.org/rfc/rfc5908
|
||||
OPTION_NTP_SERVERS6 OptionCode6 = 56
|
||||
// https://www.rfc-editor.org/rfc/rfc4833
|
||||
OPTION_NEW_POSIX_TIMEZONE OptionCode6 = 41
|
||||
OPTION_NEW_TZDB_TIMEZONE OptionCode6 = 42
|
||||
)
|
||||
|
||||
// DHCPv6 message type
|
||||
@@ -239,26 +336,32 @@ func (p Packet) PeerAddr() net.IP {
|
||||
return net.IP(p[18:34])
|
||||
}
|
||||
|
||||
func (p Packet) SetType6(hType MessageType) { p[0] = byte(hType) }
|
||||
func (p Packet) IsRelayMsg() bool {
|
||||
return p.Type6() == DHCPV6_RELAY_FORW || p.Type6() == DHCPV6_RELAY_REPL
|
||||
}
|
||||
|
||||
func (p Packet) SetTID(tid uint32) {
|
||||
func (p *Packet) SetType6(hType MessageType) {
|
||||
(*p)[0] = byte(hType)
|
||||
}
|
||||
|
||||
func (p *Packet) SetTID(tid uint32) {
|
||||
tidBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(tidBytes, tid)
|
||||
p[1] = tidBytes[1]
|
||||
p[2] = tidBytes[2]
|
||||
p[3] = tidBytes[3]
|
||||
(*p)[1] = tidBytes[1]
|
||||
(*p)[2] = tidBytes[2]
|
||||
(*p)[3] = tidBytes[3]
|
||||
}
|
||||
|
||||
func (p Packet) SetHopCount(hops byte) {
|
||||
p[1] = hops
|
||||
func (p *Packet) SetHopCount(hops byte) {
|
||||
(*p)[1] = hops
|
||||
}
|
||||
|
||||
func (p Packet) SetLinkAddr(linkAddr net.IP) {
|
||||
copy(p[2:18], linkAddr)
|
||||
func (p *Packet) SetLinkAddr(linkAddr net.IP) {
|
||||
copy((*p)[2:18], linkAddr)
|
||||
}
|
||||
|
||||
func (p Packet) SetPeerAddr(peerAddr net.IP) {
|
||||
copy(p[18:34], peerAddr)
|
||||
func (p *Packet) SetPeerAddr(peerAddr net.IP) {
|
||||
copy((*p)[18:34], peerAddr)
|
||||
}
|
||||
|
||||
func NewPacket6(opCode MessageType, tid uint32) Packet {
|
||||
@@ -284,20 +387,175 @@ type Option6 struct {
|
||||
| (option-len octets) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
func (p *Packet) AddOption6(o Option6) {
|
||||
buf := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(buf, uint16(o.Code))
|
||||
*p = append(*p, buf...)
|
||||
binary.BigEndian.PutUint16(buf, uint16(len(o.Value)))
|
||||
*p = append(*p, buf...)
|
||||
*p = append(*p, o.Value...)
|
||||
func optionToBytes(o Option6) []byte {
|
||||
buf := make([]byte, 4)
|
||||
binary.BigEndian.PutUint16(buf[0:2], uint16(o.Code))
|
||||
binary.BigEndian.PutUint16(buf[2:4], uint16(len(o.Value)))
|
||||
buf = append(buf, o.Value...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func optionsToBytes(opts []Option6) []byte {
|
||||
buf := make([]byte, 0)
|
||||
for i := range opts {
|
||||
buf = append(buf, optionToBytes(opts[i])...)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func (p Packet) GetOption6s() []Option6 {
|
||||
options := make([]Option6, 0)
|
||||
offset := 4
|
||||
if p.IsRelayMsg() {
|
||||
offset = 18
|
||||
}
|
||||
i := offset
|
||||
for i < len(p) {
|
||||
code := binary.BigEndian.Uint16(p[i : i+2])
|
||||
length := binary.BigEndian.Uint16(p[i+2 : i+4])
|
||||
options = append(options, Option6{
|
||||
Code: OptionCode6(code),
|
||||
Value: p[i+4 : i+4+int(length)],
|
||||
})
|
||||
i += 4 + int(length)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// Creates a request packet that a Client would send to a server.
|
||||
func RequestPacket6(mt MessageType, tid uint32, options []Option6) Packet {
|
||||
/*func RequestPacket6(mt MessageType, tid uint32, options []Option6) Packet {
|
||||
p := NewPacket6(mt, tid)
|
||||
for _, o := range options {
|
||||
p.AddOption6(o)
|
||||
}
|
||||
return p
|
||||
}*/
|
||||
|
||||
func MakeDHCP6Reply(pkt Packet, conf *ResponseConfig) (Packet, error) {
|
||||
var msgType MessageType
|
||||
pktType := pkt.Type6()
|
||||
switch pktType {
|
||||
case DHCPV6_SOLICIT:
|
||||
msgType = DHCPV6_ADVERTISE
|
||||
case DHCPV6_REQUEST:
|
||||
msgType = DHCPV6_REPLY
|
||||
case DHCPV6_CONFIRM:
|
||||
msgType = DHCPV6_REPLY
|
||||
case DHCPV6_RENEW:
|
||||
msgType = DHCPV6_REPLY
|
||||
case DHCPV6_REBIND:
|
||||
msgType = DHCPV6_REPLY
|
||||
case DHCPV6_INFORMATION_REQUEST:
|
||||
msgType = DHCPV6_REPLY
|
||||
default:
|
||||
return nil, errors.Wrapf(errors.ErrNotSupported, "unsupported message type %d", pktType)
|
||||
}
|
||||
|
||||
return makeDHCPReplyPacket6(pkt, conf, msgType), nil
|
||||
}
|
||||
|
||||
const (
|
||||
DUID_TYPE_LINK_LAYER_ADDRESS = 3
|
||||
DUID_HARDWARE_TYPE_ETHERNET = 1
|
||||
)
|
||||
|
||||
func makeServerId(serverMac net.HardwareAddr) []byte {
|
||||
buf := make([]byte, 4)
|
||||
binary.BigEndian.PutUint16(buf[0:2], uint16(DUID_TYPE_LINK_LAYER_ADDRESS))
|
||||
binary.BigEndian.PutUint16(buf[2:4], uint16(DUID_HARDWARE_TYPE_ETHERNET))
|
||||
buf = append(buf, serverMac[:6]...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func makeIAAddr(ip net.IP, preferLT, validLT uint32, opts []Option6) []byte {
|
||||
buf := make([]byte, 24)
|
||||
copy(buf[0:16], ip.To16())
|
||||
binary.BigEndian.PutUint32(buf[16:20], preferLT)
|
||||
binary.BigEndian.PutUint32(buf[20:24], validLT)
|
||||
buf = append(buf, optionsToBytes(opts)...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func responseIANA(buf []byte, opts []Option6) []byte {
|
||||
log.Debugf("responseIANA buf %d", len(buf))
|
||||
if len(buf) > 12 {
|
||||
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)
|
||||
buf = append(buf, optionsToBytes(opts)...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func makeIPv6s(ips []net.IP) []byte {
|
||||
buf := make([]byte, 0)
|
||||
for _, ip := range ips {
|
||||
ip6 := ip.To16()
|
||||
if ip6 == nil {
|
||||
continue
|
||||
}
|
||||
buf = append(buf, ip6...)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func makeDHCPReplyPacket6(pkt Packet, conf *ResponseConfig, msgType MessageType) Packet {
|
||||
log.Debugf("makeDHCPReplyPacket6 msgType %d tid %x", msgType, pkt.TID())
|
||||
|
||||
resp := NewPacket6(msgType, pkt.TID())
|
||||
originOpts := pkt.GetOption6s()
|
||||
getOption := func(code OptionCode6) Option6 {
|
||||
for _, o := range originOpts {
|
||||
if o.Code == code {
|
||||
return o
|
||||
}
|
||||
}
|
||||
return Option6{}
|
||||
}
|
||||
|
||||
options := make([]Option6, 0)
|
||||
|
||||
// copy clientID
|
||||
options = append(options, getOption(DHCPV6_OPTION_CLIENTID))
|
||||
// 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)
|
||||
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{
|
||||
{
|
||||
Code: DHCPV6_OPTION_STATUS_CODE,
|
||||
Value: []byte{0, 0, 'S', 'u', 'c', 'c', 'e', 's', 's'},
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
if len(conf.DNSServers6) > 0 {
|
||||
options = append(options, Option6{
|
||||
Code: OPTION_DNS_SERVERS,
|
||||
Value: makeIPv6s(conf.DNSServers6),
|
||||
})
|
||||
}
|
||||
|
||||
if len(conf.NTPServers6) > 0 {
|
||||
options = append(options, Option6{
|
||||
Code: OPTION_SNTP_SERVERS,
|
||||
Value: makeIPv6s(conf.NTPServers6),
|
||||
})
|
||||
}
|
||||
|
||||
resp = append(resp, optionsToBytes(options)...)
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
+30
-24
@@ -68,8 +68,8 @@ const (
|
||||
|
||||
bpfProcDhcpResp6 uint8 = 8
|
||||
bpfProcICMPv6 uint8 = 11
|
||||
bpfProcReadPkt6 uint8 = 14
|
||||
bpfProcEnd6 uint8 = 15
|
||||
bpfProcReadPkt6 uint8 = 17
|
||||
bpfProcEnd6 uint8 = 18
|
||||
|
||||
bpfProcReadPkt4 uint8 = 14
|
||||
bpfProcEnd4 uint8 = 15
|
||||
@@ -128,29 +128,35 @@ var (
|
||||
&bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: udpProtocol, SkipTrue: bpfGoto(4, bpfProcICMPv6), SkipFalse: bpfContinue},
|
||||
/* 4 load 14 + 40 + 0 (UDP src port), 2 bytes */
|
||||
bpf.LoadAbsolute{Off: 54, Size: 2},
|
||||
/* 5 if udp_src_port != 547 then jump to ipv6_resp/21(19+2) else continue */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 547, SkipTrue: bpfGoto(6, bpfProcDhcpResp), SkipFalse: bpfContinue},
|
||||
/* 5 if udp_src_port != 546 then jump to ipv6_resp/21(19+2) else continue */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 546, SkipTrue: bpfGoto(6, bpfProcDhcpResp), SkipFalse: bpfContinue},
|
||||
/* 6 load 14 + 40 + 2 (udp dst port), 2 bytes */
|
||||
bpf.LoadAbsolute{Off: 56, Size: 2},
|
||||
/* 7 if udp_dst_port == 546 then jump to read/24(21+3) else jump to end/25(21+4) */
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 546, SkipTrue: bpfGoto(8, bpfProcReadPkt6), SkipFalse: bpfGoto(8, bpfProcEnd6)},
|
||||
/* 8 [dhcpv6_resp] if udp_src_port != 546 then jump to end/25(22+3) else continue, which means a UDP response */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 546, SkipTrue: bpfGoto(9, bpfProcEnd6), SkipFalse: bpfContinue},
|
||||
/* 7 if udp_dst_port == 547 then jump to readPkt6 else jump to end */
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 547, SkipTrue: bpfGoto(8, bpfProcReadPkt6), SkipFalse: bpfGoto(8, bpfProcEnd6)},
|
||||
/* 8 [dhcpv6_resp] if udp_src_port != 547 then jump to end else continue, which means a DHCPv6 response */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 547, SkipTrue: bpfGoto(9, bpfProcEnd6), SkipFalse: bpfContinue},
|
||||
/* 9 load 14 + 40 + 2 (udp dst port), 2 bytes */
|
||||
bpf.LoadAbsolute{Off: 56, Size: 2},
|
||||
/* 10 if udp_dst_port != 547 then jump to end/25(24+1) else jump to read/ */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 547, SkipTrue: bpfGoto(11, bpfProcEnd6), SkipFalse: bpfGoto(11, bpfProcReadPkt6)},
|
||||
/* 10 if udp_dst_port != 546 then jump to end else jump to readPkt6 */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 546, SkipTrue: bpfGoto(11, bpfProcEnd6), SkipFalse: bpfGoto(11, bpfProcReadPkt6)},
|
||||
|
||||
/* 11 [icmp6] if ip_proto != ICMP then jump to [end]/24(17 + 7) else continue */
|
||||
/* 11 [icmp6] if ip_proto != ICMP then jump to [end] else continue */
|
||||
&bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: icmpProtocol, SkipTrue: bpfGoto(12, bpfProcEnd6), SkipFalse: bpfContinue},
|
||||
/* 12 [icmp6 type] load 14 + 40 + 0 (ICMPv6 type), 1 bytes */
|
||||
bpf.LoadAbsolute{Off: 54, Size: 1},
|
||||
/* 13 [Router Solicitation] if icmp6_type == 133 then jump to [read] else [end] */
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 133, SkipTrue: bpfGoto(14, bpfProcReadPkt6), SkipFalse: bpfGoto(14, bpfProcEnd6)},
|
||||
/* 13 [Router Solicitation] if icmp6_type == 133 then jump to [read] else [continue] */
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 133, SkipTrue: bpfGoto(14, bpfProcReadPkt6), SkipFalse: bpfContinue},
|
||||
/* 14 [Router Advertisement] if icmp6_type == 134 then jump to [read] else [continue] */
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 134, SkipTrue: bpfGoto(15, bpfProcReadPkt6), SkipFalse: bpfContinue},
|
||||
/* 15 [Neightbor Solicitation] if icmp6_type == 135 then jump to [read] else [continue] */
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 135, SkipTrue: bpfGoto(16, bpfProcReadPkt6), SkipFalse: bpfContinue},
|
||||
/* 16 [Neighbor Advertisement] if icmp6_type == 136 then jump to [read] else [end] */
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 136, SkipTrue: bpfGoto(17, bpfProcReadPkt6), SkipFalse: bpfGoto(17, bpfProcEnd6)},
|
||||
|
||||
/* 14 [read] return the whole packet */
|
||||
/* 17 [read] return the whole packet */
|
||||
bpf.RetConstant{Val: 0x40000},
|
||||
/* 15 [end] return none */
|
||||
/* 18 [end] return none */
|
||||
bpf.RetConstant{Val: 0x0},
|
||||
}
|
||||
)
|
||||
@@ -285,7 +291,7 @@ func (s *DHCP6Server) serveDHCP(handler DHCP6Handler) error {
|
||||
|
||||
if addr.Port == icmpRAFakePort {
|
||||
// receive a RA solication
|
||||
resp, err := handler.ServeRA(pkt, mac, addr)
|
||||
resp, gwIp, gwMac, err := handler.ServeRA(pkt, mac, addr)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP6] handler ServeRA error: %s", err)
|
||||
return
|
||||
@@ -295,20 +301,21 @@ func (s *DHCP6Server) serveDHCP(handler DHCP6Handler) error {
|
||||
return
|
||||
}
|
||||
|
||||
//log.Debugf("[DHCP] send response packet: %s to interface: %#v", resp.DebugString(), intf)
|
||||
err = s.conn.SendDHCP(resp, addr, mac)
|
||||
// RA should be sent to FF02::1 from gwIP
|
||||
err = s.conn.SendICMP6(resp, gwIp, gwMac, mac)
|
||||
if err != nil {
|
||||
log.Errorf("[DHCP] failed to response packet for %s: %v", pkt.CHAddr(), err)
|
||||
log.Errorf("[DHCP6] failed to response packet for ICMP6 message: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp, targets, err := handler.ServeDHCP(pkt, mac, addr)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP] handler serve error: %s", err)
|
||||
log.Warningf("[DHCP6] handler serve error: %s", err)
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
// log.Warningf("[DHCP] hander response null packet")
|
||||
log.Warningf("[DHCP6] hander response null packet")
|
||||
return
|
||||
}
|
||||
if len(targets) > 0 {
|
||||
@@ -316,15 +323,14 @@ func (s *DHCP6Server) serveDHCP(handler DHCP6Handler) error {
|
||||
for _, target := range targets {
|
||||
log.Debugf("[DHCP6] Send packet back to %s", target)
|
||||
targetUdpAddr.IP = net.ParseIP(target)
|
||||
resp.SetGIAddr(targetUdpAddr.IP)
|
||||
if err = s.conn.SendDHCP(resp, &targetUdpAddr, mac); err != nil {
|
||||
if err = s.conn.SendDHCP6(resp, &targetUdpAddr, mac); err != nil {
|
||||
log.Errorf("[DHCP6] failed to response packet for %s: %v", pkt.CHAddr(), err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
//log.Debugf("[DHCP] send response packet: %s to interface: %#v", resp.DebugString(), intf)
|
||||
if err = s.conn.SendDHCP(resp, addr, mac); err != nil {
|
||||
if err = s.conn.SendDHCP6(resp, addr, mac); err != nil {
|
||||
log.Errorf("[DHCP6] failed to response packet for %s: %v", pkt.CHAddr(), err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
@@ -131,22 +132,31 @@ func Netlen2Mask(netmasklen int) string {
|
||||
return netutils.Netlen2Mask(netmasklen)
|
||||
}
|
||||
|
||||
func addRoute(routes [][]string, net, gw string) [][]string {
|
||||
for _, rt := range routes {
|
||||
if rt[0] == net {
|
||||
return routes
|
||||
func addRoute(routes []dhcp.SRouteInfo, net, gw string) []dhcp.SRouteInfo {
|
||||
route, _ := dhcp.ParseRouteInfo([]string{net, gw})
|
||||
if route != nil {
|
||||
for _, rt := range routes {
|
||||
if rt.Prefix.String() == route.Prefix.String() && rt.PrefixLen == route.PrefixLen {
|
||||
return routes
|
||||
}
|
||||
}
|
||||
}
|
||||
return append(routes, []string{net, gw})
|
||||
}
|
||||
|
||||
func extendRoutes(routes [][]string, nicRoutes []types.SRoute) [][]string {
|
||||
for i := 0; i < len(nicRoutes); i++ {
|
||||
routes = addRoute(routes, nicRoutes[i][0], nicRoutes[i][1])
|
||||
// not found
|
||||
routes = append(routes, *route)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
func extendRoutes(routes4, routes6 []dhcp.SRouteInfo, nicRoutes []types.SRoute) ([]dhcp.SRouteInfo, []dhcp.SRouteInfo) {
|
||||
for i := 0; i < len(nicRoutes); i++ {
|
||||
if regutils.MatchCIDR6(nicRoutes[i][0]) {
|
||||
routes6 = addRoute(routes6, nicRoutes[i][0], nicRoutes[i][1])
|
||||
} else {
|
||||
routes4 = addRoute(routes4, nicRoutes[i][0], nicRoutes[i][1])
|
||||
}
|
||||
}
|
||||
return routes4, routes6
|
||||
}
|
||||
|
||||
func isExitAddress(ip string) bool {
|
||||
ipv4, err := netutils.NewIPV4Addr(ip)
|
||||
if err != nil {
|
||||
@@ -156,28 +166,33 @@ func isExitAddress(ip string) bool {
|
||||
return netutils.IsExitAddress(ipv4)
|
||||
}
|
||||
|
||||
func AddNicRoutes(routes [][]string, nicDesc *types.SServerNic, mainIp string, nicCnt int) [][]string {
|
||||
func AddNicRoutes(routes4 []dhcp.SRouteInfo, routes6 []dhcp.SRouteInfo, nicDesc *types.SServerNic, mainIp string, mainIp6 string, nicCnt int) ([]dhcp.SRouteInfo, []dhcp.SRouteInfo) {
|
||||
// always add static routes, even if this is the default NIC
|
||||
// if mainIp == nicDesc.Ip {
|
||||
// return routes
|
||||
// }
|
||||
if len(nicDesc.Routes) > 0 {
|
||||
routes = extendRoutes(routes, nicDesc.Routes)
|
||||
routes4, routes6 = extendRoutes(routes4, routes6, nicDesc.Routes)
|
||||
} else if len(nicDesc.Gateway) > 0 && !isExitAddress(nicDesc.Ip) &&
|
||||
nicCnt == 2 && nicDesc.Ip != mainIp && isExitAddress(mainIp) {
|
||||
for _, pref := range netutils.GetPrivateIPRanges() {
|
||||
prefs := pref.ToPrefixes()
|
||||
for _, p := range prefs {
|
||||
routes = addRoute(routes, p.String(), nicDesc.Gateway)
|
||||
routes4 = addRoute(routes4, p.String(), nicDesc.Gateway)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if nicDesc.Ip == mainIp {
|
||||
if len(mainIp) > 0 && nicDesc.Ip == mainIp {
|
||||
// always add 169.254.169.254 for default NIC
|
||||
routes = addRoute(routes, "169.254.169.254/32", "0.0.0.0")
|
||||
routes4 = addRoute(routes4, "169.254.169.254/32", "0.0.0.0")
|
||||
}
|
||||
return routes
|
||||
if len(mainIp6) > 0 && nicDesc.Ip6 == mainIp6 {
|
||||
routes6 = addRoute(routes6, "fd00:ec2::254/128", "::")
|
||||
routes6 = addRoute(routes6, "fe80::a9fe:a9fe/128", "::")
|
||||
}
|
||||
|
||||
return routes4, routes6
|
||||
}
|
||||
|
||||
func GetNicDns(nicdesc *types.SServerNic) []string {
|
||||
@@ -324,6 +339,14 @@ func (n *SNetInterface) GetMac() string {
|
||||
return n.mac
|
||||
}
|
||||
|
||||
func (n *SNetInterface) GetHardwareAddr() net.HardwareAddr {
|
||||
mac, err := net.ParseMAC(n.mac)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return mac
|
||||
}
|
||||
|
||||
func (n *SNetInterface) GetAllMacs() []string {
|
||||
macs := make([]string, 0, len(n.BondingSlaves)+1)
|
||||
find := false
|
||||
|
||||
Reference in New Issue
Block a user