mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-30 17:13:08 +08:00
fix: dhcpv6 support, initial support (#22820)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -234,7 +234,7 @@ func init() {
|
||||
|
||||
fmt.Println("[Slave Addresses]")
|
||||
for _, addr := range netIf.GetSlaveAddresses() {
|
||||
fmt.Printf("%s/%s\n", addr[0], addr[1])
|
||||
fmt.Printf("%s/%d\n", addr.Addr, addr.MaskLen)
|
||||
}
|
||||
fmt.Println("[Routes]")
|
||||
for _, r := range netIf.GetRouteSpecs() {
|
||||
|
||||
@@ -32,6 +32,7 @@ func init() {
|
||||
cmd.Perform("syncstatus", &options.SecgroupIdOptions{})
|
||||
cmd.Perform("private", &options.SecgroupIdOptions{})
|
||||
cmd.Perform("add-rule", &options.SecgroupsAddRuleOptions{})
|
||||
cmd.Perform("clone", &options.SecgroupCloneOptions{})
|
||||
cmd.Perform("change-owner", &options.SecgroupChangeOwnerOptions{})
|
||||
cmd.Perform("import-rules", &options.SecgroupImportRulesOptions{})
|
||||
cmd.PerformClass("clean", &options.SecgroupCleanOptions{})
|
||||
|
||||
@@ -62,10 +62,10 @@ func relayMain() error {
|
||||
return errors.Error("Missing DHCP relay server")
|
||||
}
|
||||
|
||||
srv, err := hostdhcp.NewGuestDHCPServer(options.Interface, options.Port, []string{
|
||||
options.Relay, "67",
|
||||
})
|
||||
|
||||
relayConfig := &hostdhcp.SDHCPRelayUpstream{}
|
||||
relayConfig.IP = options.Relay
|
||||
relayConfig.Port = 67
|
||||
srv, err := hostdhcp.NewGuestDHCPServer(options.Interface, options.Port, relayConfig)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "NewGuestDHCPServer")
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
|
||||
"yunion.io/x/onecloud/pkg/util/ctx"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
)
|
||||
|
||||
@@ -70,7 +71,7 @@ type dhcpRequest struct {
|
||||
netConfig *types.SNetworkConfig
|
||||
}
|
||||
|
||||
func (h *DHCPHandler) ServeDHCP(ctx context.Context, pkt dhcp.Packet, _ *net.UDPAddr, _ *net.Interface) (dhcp.Packet, []string, error) {
|
||||
func (h *DHCPHandler) ServeDHCP(pkt dhcp.Packet, _ net.HardwareAddr, _ *net.UDPAddr) (dhcp.Packet, []string, error) {
|
||||
req, err := h.newRequest(pkt, h.baremetalManager)
|
||||
if err != nil {
|
||||
log.Errorf("[DHCP] new request by packet error: %v", err)
|
||||
@@ -82,7 +83,7 @@ func (h *DHCPHandler) ServeDHCP(ctx context.Context, pkt dhcp.Packet, _ *net.UDP
|
||||
return nil, nil, fmt.Errorf("Request not from a DHCP relay, ignore mac: %s", req.ClientMac)
|
||||
}
|
||||
log.Infof("[DHCP] from relay %s packet, mac: %s", req.RelayAddr, req.ClientMac)
|
||||
conf, targets, err := req.fetchConfig(ctx, h.baremetalManager.GetClientSession())
|
||||
conf, targets, err := req.fetchConfig(ctx.CtxWithTime(), h.baremetalManager.GetClientSession())
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "fetchConfig for %s", req.ClientMac.String())
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package hostinfo
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
@@ -88,14 +87,14 @@ func (n *SNIC) setupSlaveIp(ctx context.Context, gatewayIp string, maskLen byte)
|
||||
bridgeIf := netutils2.NewNetInterface(n.Bridge)
|
||||
slaveAddrs := bridgeIf.GetSlaveAddresses()
|
||||
var curGatewayIp string
|
||||
var curMaskLen string
|
||||
var curMaskLen int
|
||||
isMaskUpdate := false
|
||||
for i := range slaveAddrs {
|
||||
addr := slaveAddrs[i]
|
||||
curGatewayIp = addr[0]
|
||||
curMaskLen = addr[1]
|
||||
curGatewayIp = addr.Addr
|
||||
curMaskLen = addr.MaskLen
|
||||
if curGatewayIp == gatewayIp {
|
||||
if curMaskLen == fmt.Sprintf("%d", maskLen) {
|
||||
if curMaskLen == int(maskLen) {
|
||||
// already configured, skip
|
||||
return nil
|
||||
} else {
|
||||
@@ -104,8 +103,8 @@ func (n *SNIC) setupSlaveIp(ctx context.Context, gatewayIp string, maskLen byte)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := n.BridgeDev.SetupSlaveAddresses([][]string{
|
||||
{gatewayIp, fmt.Sprintf("%d", maskLen)},
|
||||
if err := n.BridgeDev.SetupSlaveAddresses([]netutils2.SNicAddress{
|
||||
{Addr: gatewayIp, MaskLen: int(maskLen)},
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "SetupSlaveAddresses")
|
||||
}
|
||||
@@ -114,13 +113,13 @@ func (n *SNIC) setupSlaveIp(ctx context.Context, gatewayIp string, maskLen byte)
|
||||
}
|
||||
if isMaskUpdate {
|
||||
brName := n.BridgeDev.Bridge()
|
||||
logPrefix := fmt.Sprintf("%s slave address %s mask is update from %s to %d", brName, gatewayIp, curMaskLen, maskLen)
|
||||
addr := fmt.Sprintf("%s/%s", gatewayIp, curMaskLen)
|
||||
logPrefix := fmt.Sprintf("%s slave address %s mask is update from %d to %d", brName, gatewayIp, curMaskLen, maskLen)
|
||||
addr := fmt.Sprintf("%s/%d", gatewayIp, curMaskLen)
|
||||
log.Infof("%s: delete addr %s", logPrefix, addr)
|
||||
if err := iproute2.NewAddress(n.BridgeDev.Bridge(), addr).Del().Err(); err != nil {
|
||||
log.Warningf("%s: delete addr %s: %v", logPrefix, addr, err)
|
||||
}
|
||||
curMaskLenInt, _ := strconv.Atoi(curMaskLen)
|
||||
curMaskLenInt := curMaskLen
|
||||
if err := n.deleteMasqueradeRule(ctx, gatewayIp, byte(curMaskLenInt)); err != nil {
|
||||
log.Warningf("%s: delete iptables masqueradeRule: %v", logPrefix, err)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package hostbridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -45,9 +44,9 @@ type IBridgeDriver interface {
|
||||
GetVlanId() int
|
||||
FetchConfig()
|
||||
Setup(IBridgeDriver) error
|
||||
SetupAddresses(net.IPMask) error
|
||||
SetupSlaveAddresses([][]string) error
|
||||
SetupRoutes(routes []iproute2.RouteSpec, add bool) error
|
||||
SetupAddresses() error
|
||||
SetupSlaveAddresses([]netutils2.SNicAddress) error
|
||||
SetupRoutes(routes []iproute2.RouteSpec, add bool, dev string) error
|
||||
BringupInterface() error
|
||||
|
||||
Exists() (bool, error)
|
||||
@@ -74,12 +73,16 @@ type IBridgeDriver interface {
|
||||
type SBaseBridgeDriver struct {
|
||||
bridge *netutils2.SNetInterface
|
||||
ip string
|
||||
ip6 string
|
||||
inter *netutils2.SNetInterface
|
||||
|
||||
maskLen int
|
||||
mask6Len int
|
||||
|
||||
drv IBridgeDriver
|
||||
}
|
||||
|
||||
func NewBaseBridgeDriver(bridge, inter, ip string) (*SBaseBridgeDriver, error) {
|
||||
func NewBaseBridgeDriver(bridge, inter, ip string, maskLen int, ip6 string, mask6Len int) (*SBaseBridgeDriver, error) {
|
||||
var bd = new(SBaseBridgeDriver)
|
||||
bd.bridge = netutils2.NewNetInterface(bridge)
|
||||
if len(inter) > 0 {
|
||||
@@ -88,6 +91,9 @@ func NewBaseBridgeDriver(bridge, inter, ip string) (*SBaseBridgeDriver, error) {
|
||||
return nil, fmt.Errorf("%s not exists", inter)
|
||||
}
|
||||
bd.ip = ip
|
||||
bd.maskLen = maskLen
|
||||
bd.ip6 = ip6
|
||||
bd.mask6Len = mask6Len
|
||||
var enableGso bool
|
||||
if len(options.HostOptions.EthtoolEnableGsoInterfaces) > 0 {
|
||||
if utils.IsInStringArray(bridge, options.HostOptions.EthtoolEnableGsoInterfaces) ||
|
||||
@@ -107,14 +113,14 @@ func NewBaseBridgeDriver(bridge, inter, ip string) (*SBaseBridgeDriver, error) {
|
||||
enableGso = options.HostOptions.EthtoolEnableGso
|
||||
}
|
||||
bd.inter.SetupGso(enableGso)
|
||||
} else if len(ip) > 0 {
|
||||
} else if len(ip) > 0 || len(ip6) > 0 {
|
||||
return nil, fmt.Errorf("A bridge without interface must have no IP")
|
||||
}
|
||||
return bd, nil
|
||||
}
|
||||
|
||||
func (d *SBaseBridgeDriver) FetchConfig() {
|
||||
d.bridge.FetchConfig()
|
||||
d.bridge.FetchConfig2(d.ip, d.ip6)
|
||||
d.inter.FetchConfig()
|
||||
}
|
||||
|
||||
@@ -159,7 +165,7 @@ func (d *SBaseBridgeDriver) BringupInterface() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func trySetupSlaveAddressesRoutes(o IBridgeDriver, migrateAddrs [][]string, delRoutes []iproute2.RouteSpec, migrateRoutes []iproute2.RouteSpec) error {
|
||||
func trySetupSlaveAddressesRoutes(o IBridgeDriver, migrateAddrs []netutils2.SNicAddress, delRoutes []iproute2.RouteSpec, migrateRoutes []iproute2.RouteSpec) error {
|
||||
if len(migrateAddrs) > 0 {
|
||||
tried := 0
|
||||
const MAX_TRIES = 4
|
||||
@@ -184,7 +190,7 @@ func trySetupSlaveAddressesRoutes(o IBridgeDriver, migrateAddrs [][]string, delR
|
||||
const MAX_TRIES = 4
|
||||
errs := make([]error, 0)
|
||||
for {
|
||||
if err := o.SetupRoutes(delRoutes, false); err != nil {
|
||||
if err := o.SetupRoutes(delRoutes, false, o.Bridge()); err != nil {
|
||||
errs = append(errs, err)
|
||||
log.Errorf("delRoutes fail: %s", err)
|
||||
tried += 1
|
||||
@@ -203,7 +209,7 @@ func trySetupSlaveAddressesRoutes(o IBridgeDriver, migrateAddrs [][]string, delR
|
||||
const MAX_TRIES = 4
|
||||
errs := make([]error, 0)
|
||||
for {
|
||||
if err := o.SetupRoutes(migrateRoutes, true); err != nil {
|
||||
if err := o.SetupRoutes(migrateRoutes, true, o.Bridge()); err != nil {
|
||||
errs = append(errs, err)
|
||||
log.Errorf("SetupRoutes fail: %s", err)
|
||||
tried += 1
|
||||
@@ -222,7 +228,7 @@ func trySetupSlaveAddressesRoutes(o IBridgeDriver, migrateAddrs [][]string, delR
|
||||
|
||||
func (d *SBaseBridgeDriver) MigrateSlaveConfigs(o IBridgeDriver) error {
|
||||
if d.inter != nil {
|
||||
migrateAddrs := make([][]string, 0)
|
||||
migrateAddrs := make([]netutils2.SNicAddress, 0)
|
||||
migrateRoutes := make([]iproute2.RouteSpec, 0)
|
||||
delRoutes := make([]iproute2.RouteSpec, 0)
|
||||
{
|
||||
@@ -234,16 +240,16 @@ func (d *SBaseBridgeDriver) MigrateSlaveConfigs(o IBridgeDriver) error {
|
||||
log.Infof("to migrate routes: %s slaveAddress: %s", jsonutils.Marshal(routes), jsonutils.Marshal(slaveAddrs))
|
||||
|
||||
for i := range slaveAddrs {
|
||||
if strings.HasPrefix(slaveAddrs[i][0], "fe80:") || strings.HasPrefix(slaveAddrs[i][0], "169.254.") {
|
||||
if strings.HasPrefix(slaveAddrs[i].Addr, "fe80:") || strings.HasPrefix(slaveAddrs[i].Addr, "169.254.") {
|
||||
// skip link local address
|
||||
continue
|
||||
}
|
||||
if slaveAddrs[i][0] == d.bridge.Addr {
|
||||
if slaveAddrs[i].Addr == d.bridge.Addr || slaveAddrs[i].Addr == d.bridge.Addr6 {
|
||||
continue
|
||||
}
|
||||
find := false
|
||||
for j := range currentSlaves {
|
||||
if slaveAddrs[i][0] == currentSlaves[j][0] && slaveAddrs[i][1] == currentSlaves[j][1] {
|
||||
if slaveAddrs[i].Addr == currentSlaves[j].Addr && slaveAddrs[i].MaskLen == currentSlaves[j].MaskLen {
|
||||
find = true
|
||||
break
|
||||
}
|
||||
@@ -270,7 +276,7 @@ func (d *SBaseBridgeDriver) MigrateSlaveConfigs(o IBridgeDriver) error {
|
||||
}
|
||||
if !find {
|
||||
for j := range slaveAddrs {
|
||||
if routes[i].Dst.String() == addr2Prefix(slaveAddrs[j][0], slaveAddrs[j][1]) {
|
||||
if routes[i].Dst.String() == addr2Prefix(slaveAddrs[j].Addr, slaveAddrs[j].MaskLen) {
|
||||
find = true
|
||||
break
|
||||
}
|
||||
@@ -290,7 +296,7 @@ func (d *SBaseBridgeDriver) MigrateSlaveConfigs(o IBridgeDriver) error {
|
||||
}
|
||||
}
|
||||
{
|
||||
err := d.inter.ClearAddrs()
|
||||
err := d.inter.Reset()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ClearAddrs")
|
||||
}
|
||||
@@ -318,7 +324,7 @@ func (d *SBaseBridgeDriver) ConfirmToConfig() (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
if exist {
|
||||
d.bridge.FetchConfig()
|
||||
d.bridge.FetchConfig2(d.ip, d.ip6)
|
||||
if len(d.ip) > 0 {
|
||||
if len(d.bridge.Addr) == 0 {
|
||||
log.Infof("bridge %s has no ip assignment initially", d.bridge)
|
||||
@@ -349,6 +355,36 @@ func (d *SBaseBridgeDriver) ConfirmToConfig() (bool, error) {
|
||||
return false, fmt.Errorf("%s should have address in 169.254.0.0/16", d.bridge)
|
||||
}
|
||||
}
|
||||
if len(d.ip6) > 0 {
|
||||
if len(d.bridge.Addr6) == 0 {
|
||||
log.Infof("bridge %s has no ipv6 assignment initially", d.bridge)
|
||||
if len(d.inter.Addr6) == 0 {
|
||||
return false, fmt.Errorf("Neither %s nor %s owner ipv6 address %s",
|
||||
d.inter, d.bridge, d.ip6)
|
||||
}
|
||||
if d.inter.Addr6 != d.ip6 {
|
||||
return false, fmt.Errorf("%s!=%s, %s not same as config",
|
||||
d.ip6, d.inter.Addr6, d.inter)
|
||||
}
|
||||
log.Infof("Bridge ipv6 address is not configured")
|
||||
return false, nil
|
||||
} else {
|
||||
log.Infof("bridge %s already has ipv6 address %s", d.bridge, d.bridge.Addr6)
|
||||
}
|
||||
if d.bridge.Addr6 != d.ip6 {
|
||||
return false, fmt.Errorf("%s IP %s!=%s, mismatch", d.bridge, d.bridge.Addr6, d.ip6)
|
||||
}
|
||||
} else {
|
||||
if d.inter != nil && len(d.inter.Addr6) > 0 {
|
||||
return false, fmt.Errorf("%s should have no ipv6 address", d.inter)
|
||||
}
|
||||
if len(d.bridge.Addr6) == 0 {
|
||||
return false, nil
|
||||
}
|
||||
if !d.bridge.IsSecretInterface6() {
|
||||
return false, fmt.Errorf("%s(%s,%s) should have link local address in fe80::/10", d.bridge, d.bridge.Addr6, d.bridge.Addr6LinkLocal)
|
||||
}
|
||||
}
|
||||
infs, err := d.drv.Interfaces()
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -369,13 +405,36 @@ func (d *SBaseBridgeDriver) ConfirmToConfig() (bool, error) {
|
||||
if len(d.ip) > 0 && (d.inter == nil || len(d.inter.Addr) == 0) {
|
||||
return false, fmt.Errorf("Interface %s not configured", d.inter)
|
||||
}
|
||||
if len(d.ip6) > 0 && (d.inter == nil || len(d.inter.Addr6) == 0) {
|
||||
return false, fmt.Errorf("Interface %s ipv6 not configured", d.inter)
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (d *SBaseBridgeDriver) SetupAddresses(mask net.IPMask) error {
|
||||
func (d *SBaseBridgeDriver) SetupAddresses() error {
|
||||
br := d.bridge.String()
|
||||
if d.inter != nil {
|
||||
// first shutdown the origin interface
|
||||
ifname := d.inter.String()
|
||||
if err := d.inter.Shutdown(); err != nil {
|
||||
return errors.Wrapf(err, "shutdown bridge %s slave ifname: %s", br, ifname)
|
||||
}
|
||||
for _, cmd := range [][]string{
|
||||
{"/sbin/ifdown", ifname},
|
||||
{"nmcli", "connection", "down", ifname},
|
||||
} {
|
||||
output, err := procutils.NewRemoteCommandAsFarAsPossible(cmd[0], cmd[1:]...).Output()
|
||||
if err != nil {
|
||||
log.Errorf("run cmd: %s, output: %s, error: %s", strings.Join(cmd, " "), string(output), err)
|
||||
} else {
|
||||
log.Infof("run cmd: %s, output: %s", strings.Join(cmd, " "), string(output))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// assign address to bridge interface
|
||||
var (
|
||||
addr string
|
||||
masklen int
|
||||
@@ -384,14 +443,20 @@ func (d *SBaseBridgeDriver) SetupAddresses(mask net.IPMask) error {
|
||||
addr, masklen = netutils2.GetSecretInterfaceAddress()
|
||||
} else {
|
||||
addr = d.ip
|
||||
masklen, _ = mask.Size()
|
||||
masklen = d.maskLen
|
||||
}
|
||||
addrStr := fmt.Sprintf("%s/%d", addr, masklen)
|
||||
if err := iproute2.NewAddress(br, addrStr).Exact().Err(); err != nil {
|
||||
addrStr := []string{
|
||||
fmt.Sprintf("%s/%d", addr, masklen),
|
||||
}
|
||||
if len(d.ip6) > 0 {
|
||||
addrStr = append(addrStr, fmt.Sprintf("%s/%d", d.ip6, d.mask6Len))
|
||||
}
|
||||
if err := iproute2.NewAddress(br, addrStr...).Exact().Err(); err != nil {
|
||||
return errors.Wrapf(err, "set bridge %s address", br)
|
||||
}
|
||||
}
|
||||
{
|
||||
// bring up the bridge interface
|
||||
brLink := iproute2.NewLink(br).Up()
|
||||
if options.HostOptions.TunnelPaddingBytes > 0 {
|
||||
mtu := 1500 + int(options.HostOptions.TunnelPaddingBytes)
|
||||
@@ -400,24 +465,27 @@ func (d *SBaseBridgeDriver) SetupAddresses(mask net.IPMask) error {
|
||||
if err := brLink.Err(); err != nil {
|
||||
return errors.Wrapf(err, "setting bridge %s up", br)
|
||||
}
|
||||
}
|
||||
if d.inter != nil {
|
||||
ifname := d.inter.String()
|
||||
if err := iproute2.NewAddress(ifname).Exact().Err(); err != nil {
|
||||
return errors.Wrapf(err, "remove addresses on slave ifname: %s", ifname)
|
||||
}
|
||||
if err := iproute2.NewLink(ifname).Up().Err(); err != nil {
|
||||
return errors.Wrapf(err, "setting bridge %s ifname %s up", br, ifname)
|
||||
if d.inter != nil {
|
||||
// bring up the origin interface
|
||||
ethLink := iproute2.NewLink(d.inter.String()).Up()
|
||||
if options.HostOptions.TunnelPaddingBytes > 0 {
|
||||
mtu := 1500 + int(options.HostOptions.TunnelPaddingBytes)
|
||||
ethLink.MTU(mtu)
|
||||
}
|
||||
if err := ethLink.Err(); err != nil {
|
||||
return errors.Wrapf(err, "setting origin interface %s up", d.inter.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SBaseBridgeDriver) SetupSlaveAddresses(slaveAddrs [][]string) error {
|
||||
func (d *SBaseBridgeDriver) SetupSlaveAddresses(slaveAddrs []netutils2.SNicAddress) error {
|
||||
br := d.bridge.String()
|
||||
addrs := make([]string, len(slaveAddrs))
|
||||
for i, slaveAddr := range slaveAddrs {
|
||||
addrs[i] = fmt.Sprintf("%s/%s", slaveAddr[0], slaveAddr[1])
|
||||
addrs[i] = fmt.Sprintf("%s/%d", slaveAddr.Addr, slaveAddr.MaskLen)
|
||||
}
|
||||
if err := iproute2.NewAddress(br, addrs...).Add().Err(); err != nil {
|
||||
return errors.Wrap(err, "move secondary addresses to bridge interface")
|
||||
@@ -425,20 +493,15 @@ func (d *SBaseBridgeDriver) SetupSlaveAddresses(slaveAddrs [][]string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *SBaseBridgeDriver) SetupRoutes(routespecs []iproute2.RouteSpec, add bool) error {
|
||||
bridgeIP := d.inter.Addr
|
||||
bridgeMask := d.inter.Mask
|
||||
br := d.bridge.String()
|
||||
func (d *SBaseBridgeDriver) SetupRoutes(routespecs []iproute2.RouteSpec, add bool, dev string) error {
|
||||
for i := 0; i < len(routespecs); i++ {
|
||||
errs := []error{}
|
||||
routespec := routespecs[i]
|
||||
if routespec.Dst.Contains(net.ParseIP(bridgeIP)) && bridgeMask.String() == routespec.Dst.Mask.String() {
|
||||
log.Infof("skip setup route: %s", routespec.String())
|
||||
continue
|
||||
}
|
||||
cmd := []string{
|
||||
"route",
|
||||
var cmd []string
|
||||
if regutils.MatchCIDR6(routespec.Dst.String()) {
|
||||
cmd = append(cmd, "-6")
|
||||
}
|
||||
cmd = append(cmd, "route")
|
||||
if add {
|
||||
cmd = append(cmd, "add")
|
||||
} else {
|
||||
@@ -448,7 +511,7 @@ func (d *SBaseBridgeDriver) SetupRoutes(routespecs []iproute2.RouteSpec, add boo
|
||||
if routespec.Gw != nil {
|
||||
cmd = append(cmd, "via", routespec.Gw.String())
|
||||
}
|
||||
cmd = append(cmd, "dev", br)
|
||||
cmd = append(cmd, "dev", dev)
|
||||
|
||||
output, err := procutils.NewRemoteCommandAsFarAsPossible("ip", cmd...).Output()
|
||||
if err != nil {
|
||||
@@ -467,21 +530,19 @@ func (d *SBaseBridgeDriver) SetupRoutes(routespecs []iproute2.RouteSpec, add boo
|
||||
return nil
|
||||
}
|
||||
|
||||
func addr2Prefix(addrStr string, maskLenStr string) string {
|
||||
func addr2Prefix(addrStr string, maskLen int) string {
|
||||
if regutils.MatchIP6Addr(addrStr) {
|
||||
v6Addr, _ := netutils.NewIPV6Addr(addrStr)
|
||||
maskLen, _ := strconv.ParseInt(maskLenStr, 10, 64)
|
||||
netAddr := v6Addr.NetAddr(uint8(maskLen))
|
||||
return fmt.Sprintf("%s/%d", netAddr.String(), maskLen)
|
||||
} else {
|
||||
v4Addr, _ := netutils.NewIPV4Addr(addrStr)
|
||||
maskLen, _ := strconv.ParseInt(maskLenStr, 10, 64)
|
||||
netAddr := v4Addr.NetAddr(int8(maskLen))
|
||||
return fmt.Sprintf("%s/%d", netAddr.String(), maskLen)
|
||||
}
|
||||
}
|
||||
|
||||
func addr2Prefix2(addrStr string, mask net.IPMask) string {
|
||||
/*func addr2Prefix2(addrStr string, mask net.IPMask) string {
|
||||
if regutils.MatchIP6Addr(addrStr) {
|
||||
v6Addr, _ := netutils.NewIPV6Addr(addrStr)
|
||||
maskLen, _ := mask.Size()
|
||||
@@ -493,11 +554,11 @@ func addr2Prefix2(addrStr string, mask net.IPMask) string {
|
||||
netAddr := v4Addr.NetAddr(int8(maskLen))
|
||||
return fmt.Sprintf("%s/%d", netAddr.String(), maskLen)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
func (d *SBaseBridgeDriver) Setup(o IBridgeDriver) error {
|
||||
var routes []iproute2.RouteSpec
|
||||
var slaveAddrs [][]string
|
||||
var slaveAddrs []netutils2.SNicAddress
|
||||
if d.inter != nil && len(d.inter.Addr) > 0 {
|
||||
routes = d.inter.GetRouteSpecs()
|
||||
slaveAddrs = d.inter.GetSlaveAddresses()
|
||||
@@ -522,24 +583,28 @@ func (d *SBaseBridgeDriver) Setup(o IBridgeDriver) error {
|
||||
return errors.Wrap(err, "SetupInterface")
|
||||
}
|
||||
}
|
||||
if len(d.bridge.Addr) == 0 {
|
||||
if len(d.ip) > 0 {
|
||||
if err := o.SetupAddresses(d.inter.Mask); err != nil {
|
||||
return errors.Wrap(err, "SetupAddresses")
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
if len(d.bridge.Addr) == 0 && len(d.bridge.Addr6) == 0 {
|
||||
// need to do bridge setup
|
||||
if err := o.SetupAddresses(); err != nil {
|
||||
return errors.Wrap(err, "SetupAddresses")
|
||||
}
|
||||
// sleep 1 second to wait for bridge setup
|
||||
time.Sleep(1 * time.Second)
|
||||
// to setup default routes
|
||||
|
||||
if len(d.ip) > 0 || len(d.ip6) > 0 {
|
||||
setupRoutes := make([]iproute2.RouteSpec, 0)
|
||||
{
|
||||
for i := range routes {
|
||||
find := false
|
||||
if !find {
|
||||
if routes[i].Dst.String() == addr2Prefix2(d.ip, d.inter.Mask) {
|
||||
if routes[i].Dst.String() == addr2Prefix(d.ip, d.maskLen) || routes[i].Dst.String() == addr2Prefix(d.ip6, d.mask6Len) {
|
||||
find = true
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
for j := range slaveAddrs {
|
||||
if routes[i].Dst.String() == addr2Prefix(slaveAddrs[j][0], slaveAddrs[j][1]) {
|
||||
if routes[i].Dst.String() == addr2Prefix(slaveAddrs[j].Addr, slaveAddrs[j].MaskLen) {
|
||||
find = true
|
||||
break
|
||||
}
|
||||
@@ -547,18 +612,23 @@ func (d *SBaseBridgeDriver) Setup(o IBridgeDriver) error {
|
||||
}
|
||||
if !find {
|
||||
// need to migrate route
|
||||
log.Infof("need to migrate route: %s", routes[i].String())
|
||||
setupRoutes = append(setupRoutes, routes[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := trySetupSlaveAddressesRoutes(o, slaveAddrs, nil, setupRoutes); err != nil {
|
||||
return errors.Wrap(err, "trySetupSlaveAddressesRoutes")
|
||||
}
|
||||
} else {
|
||||
if err := o.SetupAddresses(nil); err != nil {
|
||||
return errors.Wrap(err, "SetupAddresses nil")
|
||||
if len(setupRoutes) > 0 {
|
||||
if err := o.SetupRoutes(setupRoutes, true, d.bridge.String()); err != nil {
|
||||
return errors.Wrap(err, "SetupRoutes")
|
||||
}
|
||||
}
|
||||
/*if len(setupRoutes) > 0 {
|
||||
if err := trySetupSlaveAddressesRoutes(o, slaveAddrs, nil, setupRoutes); err != nil {
|
||||
return errors.Wrap(err, "trySetupSlaveAddressesRoutes")
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return o.BringupInterface()
|
||||
@@ -629,11 +699,11 @@ func (d *SBaseBridgeDriver) DisableDHCPClient() (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func NewDriver(bridgeDriver, bridge, inter, ip string) (IBridgeDriver, error) {
|
||||
func NewDriver(bridgeDriver, bridge, inter, ip string, maskLen int, ip6 string, mask6Len int) (IBridgeDriver, error) {
|
||||
if bridgeDriver == DRV_OPEN_VSWITCH {
|
||||
return NewOVSBridgeDriver(bridge, inter, ip)
|
||||
return NewOVSBridgeDriver(bridge, inter, ip, maskLen, ip6, mask6Len)
|
||||
} else if bridgeDriver == DRV_LINUX_BRIDGE {
|
||||
return NewLinuxBridgeDeriver(bridge, inter, ip)
|
||||
return NewLinuxBridgeDeriver(bridge, inter, ip, maskLen, ip6, mask6Len)
|
||||
}
|
||||
return nil, fmt.Errorf("Dirver %s not found", bridgeDriver)
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func NewLinuxBridgeDeriver(bridge, inter, ip string) (*SLinuxBridgeDriver, error) {
|
||||
base, err := NewBaseBridgeDriver(bridge, inter, ip)
|
||||
func NewLinuxBridgeDeriver(bridge, inter, ip string, maskLen int, ip6 string, mask6Len int) (*SLinuxBridgeDriver, error) {
|
||||
base, err := NewBaseBridgeDriver(bridge, inter, ip, maskLen, ip6, mask6Len)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -300,8 +300,8 @@ func cleanOvsBridge() {
|
||||
//ovsutils.CleanAllHiddenPorts()
|
||||
}
|
||||
|
||||
func NewOVSBridgeDriver(bridge, inter, ip string) (*SOVSBridgeDriver, error) {
|
||||
base, err := NewBaseBridgeDriver(bridge, inter, ip)
|
||||
func NewOVSBridgeDriver(bridge, inter, ip string, maskLen int, ip6 string, mask6Len int) (*SOVSBridgeDriver, error) {
|
||||
base, err := NewBaseBridgeDriver(bridge, inter, ip, maskLen, ip6, mask6Len)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -311,5 +311,5 @@ func NewOVSBridgeDriver(bridge, inter, ip string) (*SOVSBridgeDriver, error) {
|
||||
}
|
||||
|
||||
func NewOVSBridgeDriverByName(bridge string) (*SOVSBridgeDriver, error) {
|
||||
return NewOVSBridgeDriver(bridge, "", "")
|
||||
return NewOVSBridgeDriver(bridge, "", "", 0, "", 0)
|
||||
}
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
package hostdhcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -27,8 +25,6 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
)
|
||||
|
||||
const DEFAULT_DHCP_RELAY_PORT = 68
|
||||
|
||||
type recvFunc func(pkt *dhcp.Packet)
|
||||
|
||||
type SRelayCache struct {
|
||||
@@ -52,18 +48,13 @@ type SDHCPRelay struct {
|
||||
cache sync.Map
|
||||
}
|
||||
|
||||
func NewDHCPRelay(guestDHCPConn *dhcp.Conn, addrs []string) (*SDHCPRelay, error) {
|
||||
func NewDHCPRelay(guestDHCPConn *dhcp.Conn, config *SDHCPRelayUpstream) (*SDHCPRelay, error) {
|
||||
relay := new(SDHCPRelay)
|
||||
relay.guestDHCPConn = guestDHCPConn
|
||||
addr := addrs[0]
|
||||
port, err := strconv.Atoi(addrs[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Pares dhcp relay addrs error %s", err)
|
||||
}
|
||||
|
||||
log.Infof("Set Relay To Address: %s, %d", addr, port)
|
||||
relay.destaddr = net.ParseIP(addr)
|
||||
relay.destport = port
|
||||
log.Infof("Set Relay To Address: %s, %d", config.IP, config.Port)
|
||||
relay.destaddr = net.ParseIP(config.IP)
|
||||
relay.destport = config.Port
|
||||
relay.cache = sync.Map{}
|
||||
|
||||
return relay, nil
|
||||
@@ -84,12 +75,12 @@ func (r *SDHCPRelay) Setup(addr string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SDHCPRelay) ServeDHCP(ctx context.Context, pkt dhcp.Packet, addr *net.UDPAddr, intf *net.Interface) (dhcp.Packet, []string, error) {
|
||||
pkg, err := r.serveDHCPInternal(pkt, addr, intf)
|
||||
func (r *SDHCPRelay) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, []string, error) {
|
||||
pkg, err := r.serveDHCPInternal(pkt, addr)
|
||||
return pkg, nil, err
|
||||
}
|
||||
|
||||
func (r *SDHCPRelay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr, intf *net.Interface) (dhcp.Packet, error) {
|
||||
func (r *SDHCPRelay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr) (dhcp.Packet, error) {
|
||||
log.Infof("DHCP Relay Reply TO %s", pkt.CHAddr())
|
||||
v, ok := r.cache.Load(pkt.TransactionID())
|
||||
if ok {
|
||||
@@ -99,14 +90,14 @@ func (r *SDHCPRelay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr, intf *ne
|
||||
IP: pkt.CIAddr(),
|
||||
Port: val.srcPort,
|
||||
}
|
||||
if err := r.guestDHCPConn.SendDHCP(pkt, udpAddr, pkt.CHAddr(), intf); err != nil {
|
||||
if err := r.guestDHCPConn.SendDHCP(pkt, udpAddr, pkt.CHAddr()); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *SDHCPRelay) Relay(pkt dhcp.Packet, addr *net.UDPAddr, intf *net.Interface) (dhcp.Packet, error) {
|
||||
func (r *SDHCPRelay) Relay(pkt dhcp.Packet, addr *net.UDPAddr) (dhcp.Packet, error) {
|
||||
if addr.IP.Equal(r.ipv4srcAddr) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -131,6 +122,6 @@ func (r *SDHCPRelay) Relay(pkt dhcp.Packet, addr *net.UDPAddr, intf *net.Interfa
|
||||
|
||||
pkt.SetGIAddr(r.ipv4srcAddr)
|
||||
|
||||
err := r.server.GetConn().SendDHCP(pkt, &net.UDPAddr{IP: r.destaddr, Port: r.destport}, nil, intf)
|
||||
err := r.server.GetConn().SendDHCP(pkt, &net.UDPAddr{IP: r.destaddr, Port: r.destport}, nil)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
)
|
||||
|
||||
type SDHCP6Relay struct {
|
||||
server *dhcp.DHCP6Server
|
||||
OnRecv recvFunc
|
||||
|
||||
guestDHCPConn *dhcp.Conn
|
||||
ipv6srcAddr net.IP
|
||||
|
||||
destaddr net.IP
|
||||
destport int
|
||||
|
||||
cache sync.Map
|
||||
}
|
||||
|
||||
func NewDHCP6Relay(guestDHCPConn *dhcp.Conn, config *SDHCPRelayUpstream) (*SDHCP6Relay, error) {
|
||||
relay := new(SDHCP6Relay)
|
||||
relay.guestDHCPConn = guestDHCPConn
|
||||
|
||||
log.Infof("Set Relay To Address: %s, %d", config.IP, config.Port)
|
||||
relay.destaddr = net.ParseIP(config.IP)
|
||||
relay.destport = config.Port
|
||||
relay.cache = sync.Map{}
|
||||
|
||||
return relay, nil
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) Setup(addr string) error {
|
||||
r.ipv6srcAddr = net.ParseIP(addr)
|
||||
if len(r.ipv6srcAddr) == 0 {
|
||||
return fmt.Errorf("Wrong ip address %s", addr)
|
||||
}
|
||||
log.Infof("DHCP6 Relay Setup on %s %d", addr, DEFAULT_DHCP6_RELAY_PORT)
|
||||
var err error
|
||||
r.server, err = dhcp.NewDHCP6Server3(addr, DEFAULT_DHCP6_RELAY_PORT)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go r.server.ListenAndServe(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, []string, error) {
|
||||
pkg, err := r.serveDHCPInternal(pkt, addr)
|
||||
return pkg, nil, err
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) ServeRA(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, error) {
|
||||
pkg, err := r.serveDHCPInternal(pkt, addr)
|
||||
return pkg, err
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) serveDHCPInternal(pkt dhcp.Packet, _ *net.UDPAddr) (dhcp.Packet, error) {
|
||||
log.Infof("DHCP Relay Reply TO %s", pkt.CHAddr())
|
||||
v, ok := r.cache.Load(pkt.TransactionID())
|
||||
if ok {
|
||||
r.cache.Delete(pkt.TransactionID())
|
||||
val := v.(*SRelayCache)
|
||||
udpAddr := &net.UDPAddr{
|
||||
IP: pkt.CIAddr(),
|
||||
Port: val.srcPort,
|
||||
}
|
||||
if err := r.guestDHCPConn.SendDHCP(pkt, udpAddr, pkt.CHAddr()); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *SDHCP6Relay) Relay(pkt dhcp.Packet, addr *net.UDPAddr) (dhcp.Packet, error) {
|
||||
if addr.IP.Equal(r.ipv6srcAddr) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
log.Infof("Receive DHCP Relay Rquest FROM %s %s", addr.IP, pkt.CHAddr())
|
||||
// clean cache first
|
||||
var now = time.Now().Add(time.Second * -30)
|
||||
r.cache.Range(func(key, value interface{}) bool {
|
||||
v := value.(*SRelayCache)
|
||||
if v.timer.Before(now) {
|
||||
r.cache.Delete(key)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
// cache pkt info
|
||||
r.cache.Store(pkt.TransactionID(), &SRelayCache{
|
||||
mac: pkt.CHAddr(),
|
||||
srcPort: addr.Port,
|
||||
timer: time.Now(),
|
||||
})
|
||||
|
||||
pkt.SetGIAddr(r.ipv6srcAddr)
|
||||
|
||||
err := r.server.GetConn().SendDHCP(pkt, &net.UDPAddr{IP: r.destaddr, Port: r.destport}, nil)
|
||||
return nil, err
|
||||
}
|
||||
@@ -15,8 +15,6 @@
|
||||
package hostdhcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -33,7 +31,11 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
)
|
||||
|
||||
const DEFAULT_DHCP_CLIENT_PORT = 68
|
||||
const (
|
||||
DEFAULT_DHCP_SERVER_PORT = 67
|
||||
// DEFAULT_DHCP_CLIENT_PORT = 68
|
||||
DEFAULT_DHCP_RELAY_PORT = 68
|
||||
)
|
||||
|
||||
type SGuestDHCPServer struct {
|
||||
server *dhcp.DHCPServer
|
||||
@@ -43,22 +45,23 @@ type SGuestDHCPServer struct {
|
||||
iface string
|
||||
}
|
||||
|
||||
func NewGuestDHCPServer(iface string, port int, relay []string) (*SGuestDHCPServer, error) {
|
||||
type SDHCPRelayUpstream struct {
|
||||
IP string
|
||||
Port int
|
||||
}
|
||||
|
||||
func NewGuestDHCPServer(iface string, port int, relay *SDHCPRelayUpstream) (*SGuestDHCPServer, error) {
|
||||
var (
|
||||
err error
|
||||
guestdhcp = new(SGuestDHCPServer)
|
||||
)
|
||||
|
||||
if len(relay) > 0 && len(relay) != 2 {
|
||||
return nil, fmt.Errorf("Wrong dhcp relay address")
|
||||
}
|
||||
|
||||
guestdhcp.server, guestdhcp.conn, err = dhcp.NewDHCPServer2(iface, uint16(port), DEFAULT_DHCP_CLIENT_PORT)
|
||||
guestdhcp.server, guestdhcp.conn, err = dhcp.NewDHCPServer2(iface, DEFAULT_DHCP_SERVER_PORT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(relay) == 2 {
|
||||
if relay != nil {
|
||||
guestdhcp.relay, err = NewDHCPRelay(guestdhcp.conn, relay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -143,7 +146,7 @@ func GetMainNic(nics []*desc.SGuestNetwork) *desc.SGuestNetwork {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SGuestDHCPServer) getGuestConfig(
|
||||
func getGuestConfig(
|
||||
guestDesc *desc.SGuestDesc, guestNic *desc.SGuestNetwork,
|
||||
) *dhcp.ResponseConfig {
|
||||
var nicdesc = new(types.SServerNic)
|
||||
@@ -169,6 +172,13 @@ func (s *SGuestDHCPServer) getGuestConfig(
|
||||
conf.Hostname = strings.ToLower(conf.Hostname)
|
||||
conf.Domain = nicdesc.Domain
|
||||
|
||||
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)
|
||||
@@ -232,7 +242,7 @@ func (s *SGuestDHCPServer) getConfig(pkt dhcp.Packet) *dhcp.ResponseConfig {
|
||||
guestDesc, guestNic = guestman.GuestDescGetter.GetGuestNicDesc(mac, ip, port, s.iface, !isCandidate)
|
||||
}
|
||||
if guestNic != nil && !guestNic.Virtual {
|
||||
return s.getGuestConfig(guestDesc, guestNic)
|
||||
return getGuestConfig(guestDesc, guestNic)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -241,12 +251,12 @@ func (s *SGuestDHCPServer) IsDhcpPacket(pkt dhcp.Packet) bool {
|
||||
return pkt != nil && (pkt.Type() == dhcp.Request || pkt.Type() == dhcp.Discover)
|
||||
}
|
||||
|
||||
func (s *SGuestDHCPServer) ServeDHCP(ctx context.Context, pkt dhcp.Packet, addr *net.UDPAddr, intf *net.Interface) (dhcp.Packet, []string, error) {
|
||||
pkg, err := s.serveDHCPInternal(pkt, addr, intf)
|
||||
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, intf *net.Interface) (dhcp.Packet, error) {
|
||||
func (s *SGuestDHCPServer) serveDHCPInternal(pkt dhcp.Packet, addr *net.UDPAddr) (dhcp.Packet, error) {
|
||||
if !s.IsDhcpPacket(pkt) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -257,7 +267,7 @@ func (s *SGuestDHCPServer) serveDHCPInternal(pkt dhcp.Packet, addr *net.UDPAddr,
|
||||
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, intf)
|
||||
return s.relay.Relay(pkt, addr)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
// 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"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
guestman "yunion.io/x/onecloud/pkg/hostman/guestman/types"
|
||||
"yunion.io/x/onecloud/pkg/util/dhcp"
|
||||
)
|
||||
|
||||
const (
|
||||
DEFAULT_DHCP6_SERVER_PORT = 547
|
||||
// DEFAULT_DHCP_CLIENT_PORT = 68
|
||||
DEFAULT_DHCP6_RELAY_PORT = 546
|
||||
)
|
||||
|
||||
type SGuestDHCP6Server struct {
|
||||
server *dhcp.DHCP6Server
|
||||
relay *SDHCP6Relay
|
||||
conn *dhcp.Conn
|
||||
|
||||
iface string
|
||||
}
|
||||
|
||||
func NewGuestDHCP6Server(iface string, port int, relay *SDHCPRelayUpstream) (*SGuestDHCP6Server, error) {
|
||||
var (
|
||||
err error
|
||||
guestdhcp = new(SGuestDHCP6Server)
|
||||
)
|
||||
|
||||
guestdhcp.server, guestdhcp.conn, err = dhcp.NewDHCP6Server2(iface, DEFAULT_DHCP6_SERVER_PORT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if relay != nil {
|
||||
guestdhcp.relay, err = NewDHCP6Relay(guestdhcp.conn, relay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
guestdhcp.iface = iface
|
||||
return guestdhcp, nil
|
||||
}
|
||||
|
||||
func (s *SGuestDHCP6Server) Start(blocking bool) {
|
||||
log.Infof("SGuestDHCP6Server starting ...")
|
||||
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 *SGuestDHCP6Server) RelaySetup(addr string) error {
|
||||
if s.relay != nil {
|
||||
return s.relay.Setup(addr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SGuestDHCP6Server) getConfig(cliMac net.HardwareAddr, _ dhcp.Packet) *dhcp.ResponseConfig {
|
||||
if guestman.GuestDescGetter == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
ip, port = "", ""
|
||||
isCandidate = false
|
||||
)
|
||||
guestDesc, guestNic := guestman.GuestDescGetter.GetGuestNicDesc(cliMac.String(), ip, port, s.iface, isCandidate)
|
||||
if guestNic == nil {
|
||||
guestDesc, guestNic = guestman.GuestDescGetter.GetGuestNicDesc(cliMac.String(), ip, port, s.iface, !isCandidate)
|
||||
}
|
||||
if guestNic != nil && !guestNic.Virtual && len(guestNic.Ip6) > 0 {
|
||||
return getGuestConfig(guestDesc, guestNic)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SGuestDHCP6Server) ServeDHCP(pkt dhcp.Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (dhcp.Packet, []string, error) {
|
||||
pkg, err := s.serveDHCPInternal(pkt, cliMac, addr)
|
||||
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)
|
||||
if conf != nil {
|
||||
return dhcp.MakeRouterAdverPacket(conf.Gateway6, conf.PrefixLen6, uint32(conf.MTU))
|
||||
}
|
||||
return 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())
|
||||
// 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
|
||||
}
|
||||
@@ -172,7 +172,12 @@ func (h *SHostInfo) GetBridgeDev(bridge string) hostbridge.IBridgeDriver {
|
||||
|
||||
func (h *SHostInfo) StartDHCPServer() {
|
||||
for _, nic := range h.Nics {
|
||||
nic.dhcpServer.Start(false)
|
||||
if nic.dhcpServer != nil {
|
||||
nic.dhcpServer.Start(false)
|
||||
}
|
||||
if nic.dhcpServer6 != nil {
|
||||
nic.dhcpServer6.Start(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -171,22 +171,45 @@ type SNIC struct {
|
||||
Inter string
|
||||
Bridge string
|
||||
Ip string
|
||||
Ip6 string
|
||||
Wire string
|
||||
WireId string
|
||||
Mask int
|
||||
Mask6 int
|
||||
|
||||
Bandwidth int
|
||||
BridgeDev hostbridge.IBridgeDriver
|
||||
dhcpServer *hostdhcp.SGuestDHCPServer
|
||||
Bandwidth int
|
||||
BridgeDev hostbridge.IBridgeDriver
|
||||
|
||||
dhcpServer *hostdhcp.SGuestDHCPServer
|
||||
dhcpServer6 *hostdhcp.SGuestDHCP6Server
|
||||
}
|
||||
|
||||
func (n *SNIC) EnableDHCPRelay() bool {
|
||||
if len(n.Ip) == 0 {
|
||||
return false
|
||||
}
|
||||
v4Ip, err := netutils.NewIPV4Addr(n.Ip)
|
||||
if err != nil {
|
||||
log.Errorf("EnableDHCPRelay netutils.NewIPV4Addr(%s) error: %v", n.Ip, err)
|
||||
return false
|
||||
}
|
||||
if len(options.HostOptions.DhcpRelay) > 0 && !netutils.IsExitAddress(v4Ip) {
|
||||
if len(options.HostOptions.DhcpRelay) == 2 && !netutils.IsExitAddress(v4Ip) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (n *SNIC) EnableDHCP6Relay() bool {
|
||||
if len(n.Ip6) == 0 {
|
||||
return false
|
||||
}
|
||||
_, err := netutils.NewIPV6Addr(n.Ip6)
|
||||
if err != nil {
|
||||
log.Errorf("EnableDHCP6Relay netutils.NewIPV6Addr(%s) error: %v", n.Ip6, err)
|
||||
return false
|
||||
}
|
||||
if len(options.HostOptions.Dhcp6Relay) == 2 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@@ -200,7 +223,12 @@ func (n *SNIC) SetupDhcpRelay() error {
|
||||
return errors.Wrapf(err, "setup dhcp relay on ip: %s", n.Ip)
|
||||
}
|
||||
}
|
||||
log.Infof("Not enable dhcp relay on nic: %#v", n)
|
||||
if n.EnableDHCP6Relay() {
|
||||
log.Infof("Enable dhcpv6 relay on nic: %#v", n)
|
||||
if err := n.dhcpServer6.RelaySetup(n.Ip6); err != nil {
|
||||
return errors.Wrapf(err, "setup dhcpv6 relay on ip: %s", n.Ip6)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -231,26 +259,42 @@ func NewNIC(desc string) (*SNIC, error) {
|
||||
}
|
||||
nic.Inter = data[0]
|
||||
nic.Bridge = data[1]
|
||||
|
||||
if regutils.MatchIP4Addr(data[2]) {
|
||||
nic.Ip = data[2]
|
||||
if len(data) > 3 && regutils.MatchIP6Addr(data[3]) {
|
||||
nic.Ip6 = data[3]
|
||||
}
|
||||
} else if regutils.MatchIP6Addr(data[2]) {
|
||||
nic.Ip6 = data[3]
|
||||
if len(data) > 3 && regutils.MatchIP4Addr(data[3]) {
|
||||
nic.Ip = data[3]
|
||||
}
|
||||
} else {
|
||||
nic.Wire = data[2]
|
||||
}
|
||||
|
||||
nic.Bandwidth = 1000
|
||||
|
||||
log.Infof("IP %s/%s/%s", nic.Ip, nic.Bridge, nic.Inter)
|
||||
if len(nic.Ip) > 0 {
|
||||
log.Infof("IP %s/%s/%s/%s", nic.Ip, nic.Ip6, nic.Bridge, nic.Inter)
|
||||
// fetch ip and ip6 netmask from interface and bridge
|
||||
if len(nic.Ip) > 0 || len(nic.Ip6) > 0 {
|
||||
// waiting for interface assign ip
|
||||
// in case nic bonding is too slow
|
||||
var max, wait = 30, 0
|
||||
for wait < max {
|
||||
inf := netutils2.NewNetInterfaceWithExpectIp(nic.Inter, nic.Ip)
|
||||
if inf.Addr == nic.Ip {
|
||||
inf := netutils2.NewNetInterfaceWithExpectIp(nic.Inter, nic.Ip, nic.Ip6)
|
||||
if len(nic.Ip) > 0 && inf.Addr == nic.Ip {
|
||||
mask, _ := inf.Mask.Size()
|
||||
if mask > 0 {
|
||||
nic.Mask = mask
|
||||
}
|
||||
break
|
||||
}
|
||||
if len(nic.Ip6) > 0 && inf.Addr6 == nic.Ip6 {
|
||||
mask, _ := inf.Mask6.Size()
|
||||
if mask > 0 {
|
||||
nic.Mask6 = mask
|
||||
}
|
||||
}
|
||||
br := netutils2.NewNetInterface(nic.Bridge)
|
||||
if br.Addr == nic.Ip {
|
||||
@@ -258,6 +302,14 @@ func NewNIC(desc string) (*SNIC, error) {
|
||||
if nic.Mask == 0 && mask > 0 {
|
||||
nic.Mask = mask
|
||||
}
|
||||
}
|
||||
if br.Addr6 == nic.Ip6 {
|
||||
mask, _ := br.Mask6.Size()
|
||||
if nic.Mask6 == 0 && mask > 0 {
|
||||
nic.Mask6 = mask
|
||||
}
|
||||
}
|
||||
if nic.Mask > 0 || nic.Mask6 > 0 {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
@@ -272,9 +324,9 @@ func NewNIC(desc string) (*SNIC, error) {
|
||||
var err error
|
||||
|
||||
nic.BridgeDev, err = hostbridge.NewDriver(options.HostOptions.BridgeDriver,
|
||||
nic.Bridge, nic.Inter, nic.Ip)
|
||||
nic.Bridge, nic.Inter, nic.Ip, nic.Mask, nic.Ip6, nic.Mask6)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "hostbridge.NewDriver driver: %s, bridge: %s, interface: %s, ip: %s", options.HostOptions.BridgeDriver, nic.Bridge, nic.Inter, nic.Ip)
|
||||
return nil, errors.Wrapf(err, "hostbridge.NewDriver driver: %s, bridge: %s, interface: %s, ip: %s/%d, ip6: %s/%d", options.HostOptions.BridgeDriver, nic.Bridge, nic.Inter, nic.Ip, nic.Mask, nic.Ip6, nic.Mask6)
|
||||
}
|
||||
|
||||
confirm, err := nic.BridgeDev.ConfirmToConfig()
|
||||
@@ -303,14 +355,36 @@ func NewNIC(desc string) (*SNIC, error) {
|
||||
Instance().AppendHostError("dhcp client is enabled before host agent start, please disable it")
|
||||
}
|
||||
|
||||
var dhcpRelay []string
|
||||
var relayConf *hostdhcp.SDHCPRelayUpstream
|
||||
if nic.EnableDHCPRelay() {
|
||||
log.Infof("EnableDHCPRelay on nic %#v", nic)
|
||||
dhcpRelay = options.HostOptions.DhcpRelay
|
||||
relayConf = &hostdhcp.SDHCPRelayUpstream{}
|
||||
relayConf.IP = options.HostOptions.DhcpRelay[0]
|
||||
relayConf.Port, err = strconv.Atoi(options.HostOptions.DhcpRelay[1])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid relay port %s", options.HostOptions.DhcpRelay[1])
|
||||
}
|
||||
}
|
||||
nic.dhcpServer, err = hostdhcp.NewGuestDHCPServer(nic.Bridge, options.HostOptions.DhcpServerPort, dhcpRelay)
|
||||
|
||||
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, dhcpRelay)
|
||||
return nil, errors.Wrapf(err, "NewGuestDHCPServer(%s, %d, %#v)", nic.Bridge, options.HostOptions.DhcpServerPort, relayConf)
|
||||
}
|
||||
|
||||
var relayConf6 *hostdhcp.SDHCPRelayUpstream
|
||||
if nic.EnableDHCP6Relay() {
|
||||
log.Infof("EnableDHCP6Relay on nic %#v", nic)
|
||||
relayConf6 = &hostdhcp.SDHCPRelayUpstream{}
|
||||
relayConf6.IP = options.HostOptions.Dhcp6Relay[0]
|
||||
relayConf6.Port, err = strconv.Atoi(options.HostOptions.Dhcp6Relay[1])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid relay port %s", options.HostOptions.Dhcp6Relay[1])
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -123,13 +123,15 @@ type SHostOptions struct {
|
||||
SharedStorages []string `help:"Path of shared storages"`
|
||||
LVMVolumeGroups []string `help:"LVM Volume Groups(vgs)"`
|
||||
|
||||
DhcpRelay []string `help:"DHCP relay upstream"`
|
||||
DhcpRelay []string `help:"DHCP relay upstream"`
|
||||
Dhcp6Relay []string `help:"DHCPv6 relay upstream"`
|
||||
|
||||
TunnelPaddingBytes int64 `help:"Specify tunnel padding bytes" default:"0"`
|
||||
|
||||
CheckSystemServices bool `help:"Check system services (ntpd, telegraf) on startup" default:"true"`
|
||||
|
||||
DhcpServerPort int `help:"Host dhcp server bind port" default:"67"`
|
||||
Dhcp6ServerPort int `help:"Host dhcp6 server bind port" default:"547"`
|
||||
FetcherfsPath string `default:"/opt/yunion/fetchclient/bin/fetcherfs" help:"Fuse fetcherfs path"`
|
||||
FetcherfsBlockSize int `default:"16" help:"Fuse fetcherfs fetch chunk_size MB"`
|
||||
|
||||
|
||||
@@ -121,6 +121,16 @@ func (opts *SecgroupsAddRuleOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return params, nil
|
||||
}
|
||||
|
||||
type SecgroupCloneOptions struct {
|
||||
SecgroupIdOptions
|
||||
NAME string `help:"Name of new secgroup"`
|
||||
Desc string `help:"Description of new secgroup"`
|
||||
}
|
||||
|
||||
func (opts *SecgroupCloneOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(map[string]string{"name": opts.NAME, "description": opts.Desc}), nil
|
||||
}
|
||||
|
||||
type SecurityGroupCacheOptions struct {
|
||||
SecgroupIdOptions
|
||||
VPC_ID string `help:"ID or Name of vpc"`
|
||||
|
||||
@@ -239,29 +239,57 @@ Measurement,MeasurementNote,ResourceType,Database,Metric,MetricNote,MetricUnit
|
||||
"vasmi","Vasmi GPU metrics","host","telegraf","eclk","eclk, MHz",""
|
||||
"vasmi","Vasmi GPU metrics","host","telegraf","gclk","gclk, MHz",""
|
||||
"vasmi","Vasmi GPU metrics","host","telegraf","aic_power","AIC power",""
|
||||
"worker","Worker queue","worker","system","active_worker_cnt","Active Worker Count","NULL"
|
||||
"worker","Worker queue","worker","system","max_worker_count","Max Worker Count","NULL"
|
||||
"worker","Worker queue","worker","system","detach_worker_cnt","Detach worker Count","NULL"
|
||||
"worker","Worker queue","worker","system","queue_cnt","Worker Queue Count","NULL"
|
||||
"http_request","HTTP Request hit","http_request","system","duration.2xx","http code 2xxx duration","NULL"
|
||||
"http_request","HTTP Request hit","http_request","system","duration.4xx","http code 4xxx duration","NULL"
|
||||
"http_request","HTTP Request hit","http_request","system","duration.5xx","http code 5xxx duration","NULL"
|
||||
"http_request","HTTP Request hit","http_request","system","hit.2xx","http code 2xxx hit","NULL"
|
||||
"http_request","HTTP Request hit","http_request","system","hit.4xx","http code 4xxx hit","NULL"
|
||||
"http_request","HTTP Request hit","http_request","system","hit.5xx","http code 5xxx hit","NULL"
|
||||
"process","Service process stats","process","system","cpu_percent","CPU percent","NULL"
|
||||
"process","Service process stats","process","system","mem_percent","Memory percent","NULL"
|
||||
"process","Service process stats","process","system","mem_size","Memory size","NULL"
|
||||
"process","Service process stats","process","system","goroutine_num","Goroutine num","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","idle","Database Idle","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","in_use","Database InUse","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","max_idle_closed","Database max idle closed","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","max_idle_time_closed","Database max idle time closed","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","max_lifetime_closed","Database max lifetime closed","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","max_open_connections","Database max open connections","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","open_connections","Database open connections","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","wait_count","Database wait count","NULL"
|
||||
"db_stats","Database Stats","db_stats","system","wait_duration","Database wait duration","NULL"
|
||||
"worker","Worker queue","system","system","active_worker_cnt","Active Worker Count","NULL"
|
||||
"worker","Worker queue","system","system","max_worker_count","Max Worker Count","NULL"
|
||||
"worker","Worker queue","system","system","detach_worker_cnt","Detach worker Count","NULL"
|
||||
"worker","Worker queue","system","system","queue_cnt","Worker Queue Count","NULL"
|
||||
"worker","Worker queue","system","system","total_workload","Total workload","NULL"
|
||||
"worker","Worker queue","system","system","active_workload","Active workload","NULL"
|
||||
"http_request","HTTP Request hit","system","system","duration_ms_any","Accumulated request duration in milliseconds","ms"
|
||||
"http_request","HTTP Request hit","system","system","dura_ms_delta_any","Accumulated request duration in milliseconds in last interval","ms"
|
||||
"http_request","HTTP Request hit","system","system","hit_any","Accumulated request count","NULL"
|
||||
"http_request","HTTP Request hit","system","system","hit_delta_any","Accumulated request count in last interval","NULL"
|
||||
"http_request","HTTP Request hit","system","system","delay_ms_any","Average request delay in miilliseconds","ms"
|
||||
"http_request","HTTP Request hit","system","system","qps_any","Averatge request per second","NULL"
|
||||
"http_request","HTTP Request hit","system","system","duration_ms_2xx","Accumulated request duration in milliseconds for 2xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","dura_ms_delta_2xx","Accumulated request duration in milliseconds in last interval for 2xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","hit_2xx","Accumulated request count for 2xx http code","NULL"
|
||||
"http_request","HTTP Request hit","system","system","hit_delta_2xx","Accumulated request count in last interval for 2xx http code","NULL"
|
||||
"http_request","HTTP Request hit","system","system","delay_ms_2xx","Average request delay in miilliseconds for 2xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","percent_hit_2xx","Request hit weight in percentage for 2xx http code","%"
|
||||
"http_request","HTTP Request hit","system","system","percent_duration_2xx","Request duration weight in percentage for 2xx http code","%"
|
||||
"http_request","HTTP Request hit","system","system","qps_2xx","Averatge request per second for 2xx http code","NULL"
|
||||
"http_request","HTTP Request hit","system","system","duration_ms_4xx","Accumulated request duration in milliseconds for 4xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","dura_ms_delta_4xx","Accumulated request duration in milliseconds in last interval for 4xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","hit_4xx","Accumulated request count for 4xx http code","NULL"
|
||||
"http_request","HTTP Request hit","system","system","hit_delta_4xx","Accumulated request count in last interval for 4xx http code","NULL"
|
||||
"http_request","HTTP Request hit","system","system","delay_ms_4xx","Average request delay in miilliseconds for 4xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","percent_hit_4xx","Request hit weight in percentage for 4xx http code","%"
|
||||
"http_request","HTTP Request hit","system","system","percent_duration_4xx","Request duration weight in percentage for 4xx http code","%"
|
||||
"http_request","HTTP Request hit","system","system","qps_4xx","Averatge request per second for 4xx http code","NULL"
|
||||
"http_request","HTTP Request hit","system","system","duration_ms_5xx","Accumulated request duration in milliseconds for 5xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","dura_ms_delta_5xx","Accumulated request duration in milliseconds in last interval for 5xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","hit_5xx","Accumulated request count for 5xx http code","NULL"
|
||||
"http_request","HTTP Request hit","system","system","hit_delta_5xx","Accumulated request count in last interval for 5xx http code","NULL"
|
||||
"http_request","HTTP Request hit","system","system","delay_ms_5xx","Average request delay in miilliseconds for 5xx http code","ms"
|
||||
"http_request","HTTP Request hit","system","system","percent_hit_5xx","Request hit weight in percentage for 5xx http code","%"
|
||||
"http_request","HTTP Request hit","system","system","percent_duration_5xx","Request duration weight in percentage for 5xx http code","%"
|
||||
"http_request","HTTP Request hit","system","system","qps_5xx","Averatge request per second for 5xx http code","NULL"
|
||||
"process","Service process stats","system","system","cpu_percent","CPU percent","NULL"
|
||||
"process","Service process stats","system","system","mem_percent","Memory percent","NULL"
|
||||
"process","Service process stats","system","system","mem_size","Memory size","NULL"
|
||||
"process","Service process stats","system","system","goroutine_num","Goroutine num","NULL"
|
||||
"db_stats","Database Stats","system","system","idle","Database Idle","NULL"
|
||||
"db_stats","Database Stats","system","system","in_use","Database InUse","NULL"
|
||||
"db_stats","Database Stats","system","system","max_idle_closed","Database max idle closed","NULL"
|
||||
"db_stats","Database Stats","system","system","max_idle_time_closed","Database max idle time closed","NULL"
|
||||
"db_stats","Database Stats","system","system","max_lifetime_closed","Database max lifetime closed","NULL"
|
||||
"db_stats","Database Stats","system","system","max_open_connections","Database max open connections","NULL"
|
||||
"db_stats","Database Stats","system","system","open_connections","Database open connections","NULL"
|
||||
"db_stats","Database Stats","system","system","wait_count","Database wait count","NULL"
|
||||
"db_stats","Database Stats","system","system","wait_duration","Database wait duration","NULL"
|
||||
"status_probe","Resource status probe results","system","system","count","Resouce count for each status","NULL"
|
||||
"status_probe","Resource status probe results","system","system","pending_deleted","Pending deleted resource count for each status","NULL"
|
||||
"vm_cpu","Guest CPU usage","guest","telegraf","usage_active","CPU active state utilization rate","%"
|
||||
"vm_cpu","Guest CPU usage","guest","telegraf","cpu_usage_pcore","CPU utilization rate per core","%"
|
||||
"vm_cpu","Guest CPU usage","guest","telegraf","cpu_usage_idle_pcore","CPU idle rate per core","%"
|
||||
@@ -282,10 +310,18 @@ Measurement,MeasurementNote,ResourceType,Database,Metric,MetricNote,MetricUnit
|
||||
"vm_netio","Guest network traffic","guest","telegraf","bps_sent","Send traffic per second","bps"
|
||||
"vm_netio","Guest network traffic","guest","telegraf","pps_recv","Received packets per second","pps"
|
||||
"vm_netio","Guest network traffic","guest","telegraf","pps_sent","Send packets per second","pps"
|
||||
"vm_netio","Guest network traffic","guest","telegraf","bytes_sent","The total number of bytes sent by the network interface","byte"
|
||||
"vm_netio","Guest network traffic","guest","telegraf","bytes_recv","The total number of bytes received by the network interface","byte"
|
||||
"vm_netio","Guest network traffic","guest","telegraf","packets_sent","The total number of packets sent by the network interface","count"
|
||||
"vm_netio","Guest network traffic","guest","telegraf","packets_recv","The total number of packets received by the network interface","count"
|
||||
"pod_netio","Pod network traffic","container","telegraf","bps_recv","Received traffic per second","bps"
|
||||
"pod_netio","Pod network traffic","container","telegraf","bps_sent","Send traffic per second","bps"
|
||||
"pod_netio","Pod network traffic","container","telegraf","pps_recv","Received packets per second","pps"
|
||||
"pod_netio","Pod network traffic","container","telegraf","pps_sent","Send packets per second","pps"
|
||||
"pod_netio","Pod network traffic","container","telegraf","bytes_sent","The total number of bytes sent by the network interface","byte"
|
||||
"pod_netio","Pod network traffic","container","telegraf","bytes_recv","The total number of bytes received by the network interface","byte"
|
||||
"pod_netio","Pod network traffic","container","telegraf","packets_sent","The total number of packets sent by the network interface","count"
|
||||
"pod_netio","Pod network traffic","container","telegraf","packets_recv","The total number of packets received by the network interface","count"
|
||||
"cloudaccount_balance","Cloud account balance","cloudaccount","meter_db","balance","balance","NULL"
|
||||
"container_cpu","Container cpu","container","telegraf","usage_rate","Container cpu usage rate","%"
|
||||
"container_mem","Container memory","container","telegraf","usage_rate","Container memory usage rate","%"
|
||||
@@ -493,6 +529,11 @@ Measurement,MeasurementNote,ResourceType,Database,Metric,MetricNote,MetricUnit
|
||||
"oss_netio","Object storage network traffic","oss","telegraf","bps_recv","Receive byte","byte"
|
||||
"oss_netio","Object storage network traffic","oss","telegraf","bps_sent","Send byte","byte"
|
||||
"oss_req","Object store request","oss","telegraf","req_count","request count","count"
|
||||
"bucket_perf","Object storage bucket performance monitor","oss","telegraf","upload_delay_ms","Bucket upload delay in milliseconds","ms"
|
||||
"bucket_perf","Object storage bucket performance monitor","oss","telegraf","download_delay_ms","Bucket download delay in milliseconds","ms"
|
||||
"bucket_perf","Object storage bucket performance monitor","oss","telegraf","delete_delay_ms","Bucket delete delay in milliseconds","ms"
|
||||
"bucket_perf","Object storage bucket performance monitor","oss","telegraf","upload_rate_mbps","Bucket upload rate in megabits per second","Mbps"
|
||||
"bucket_perf","Object storage bucket performance monitor","oss","telegraf","download_rate_mbps","Bucket download rate in megabits per second","Mbps"
|
||||
"ping","Ping monitor","host","telegraf","packets_transmitted","used SNAT port count","count"
|
||||
"ping","Ping monitor","host","telegraf","packets_received","SNAT connection count","count"
|
||||
"ping","Ping monitor","host","telegraf","percent_packet_loss","Packet loss rate in percetile","%"
|
||||
|
||||
|
+39
-113
@@ -30,16 +30,15 @@
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
"golang.org/x/net/ipv4"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
// defined as a var so tests can override it.
|
||||
@@ -71,8 +70,10 @@ const (
|
||||
|
||||
type conn interface {
|
||||
io.Closer
|
||||
Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr, ifidx int) error
|
||||
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
|
||||
Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error)
|
||||
SetReadDeadline(t time.Time) error
|
||||
SetWriteDeadline(t time.Time) error
|
||||
}
|
||||
@@ -85,8 +86,8 @@ type Conn struct {
|
||||
ifIndex int
|
||||
}
|
||||
|
||||
func NewRawSocketConn(iface string, filter []bpf.RawInstruction, dhcpServerPort uint16) (*Conn, error) {
|
||||
conn, err := newRawSocketConn(iface, filter, dhcpServerPort)
|
||||
func NewRawSocketConn(iface string, filter []bpf.RawInstruction, serverPort uint16) (*Conn, error) {
|
||||
conn, err := newRawSocketConn(iface, filter, serverPort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -102,11 +103,11 @@ func NewSocketConn(addr string, port int) (*Conn, error) {
|
||||
}
|
||||
|
||||
// NewConn creates a Conn bound to the given UDP ip:port.
|
||||
func NewConn(addr string, disableBroadcast bool) (*Conn, error) {
|
||||
return newConn(addr, disableBroadcast, newPortableConn)
|
||||
}
|
||||
// func NewConn(addr string, disableBroadcast bool) (*Conn, error) {
|
||||
// return newConn(addr, disableBroadcast, newPortableConn)
|
||||
// }
|
||||
|
||||
func newConn(addr string, disableBroadcast bool, n func(net.IP, int, bool) (conn, error)) (*Conn, error) {
|
||||
/*func newConn(addr string, disableBroadcast bool, n func(net.IP, int, bool) (conn, error)) (*Conn, error) {
|
||||
if addr == "" {
|
||||
addr = "0.0.0.0:67"
|
||||
}
|
||||
@@ -136,7 +137,7 @@ func newConn(addr string, disableBroadcast bool, n func(net.IP, int, bool) (conn
|
||||
conn: c,
|
||||
ifIndex: ifIndex,
|
||||
}, nil
|
||||
}
|
||||
}*/
|
||||
|
||||
func ipToIfindex(ip net.IP) (int, error) {
|
||||
intfs, err := net.Interfaces()
|
||||
@@ -167,69 +168,44 @@ func (c *Conn) Close() error {
|
||||
|
||||
// RecvDHCP reads a Packet from the connection. It returns the
|
||||
// packet and the interface it was received on.
|
||||
func (c *Conn) RecvDHCP() (Packet, *net.UDPAddr, net.HardwareAddr, *net.Interface, error) {
|
||||
func (c *Conn) RecvDHCP() (Packet, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
var buf [1500]byte
|
||||
b, addr, mac, _, err := c.conn.Recv(buf[:])
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
/*if c.ifIndex != 0 && ifidx != c.ifIndex {
|
||||
log.Errorf("======= ifIndex continue, c.ifIndex: %d, ifidx: %d", c.ifIndex, ifidx)
|
||||
continue
|
||||
}*/
|
||||
pkt := Unmarshal(b)
|
||||
// intf, err := net.InterfaceByIndex(ifidx)
|
||||
// if err != nil {
|
||||
// return nil, nil, nil, err
|
||||
// }
|
||||
return pkt, addr, mac, nil
|
||||
}
|
||||
|
||||
// TODO: possibly more validation that the source lines up
|
||||
// with what the packet says.
|
||||
return pkt, addr, mac, nil, nil
|
||||
func (c *Conn) RecvDHCP6() (Packet, *net.UDPAddr, net.HardwareAddr, error) {
|
||||
var buf [1500]byte
|
||||
b, addr, mac, _, err := c.conn.Recv6(buf[:])
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
pkt := Unmarshal(b)
|
||||
return pkt, addr, mac, nil
|
||||
}
|
||||
|
||||
// SendDHCP sends pkt. The precise transmission mechanism depends
|
||||
// on pkt.txType(). intf should be the net.Interface returned by
|
||||
// RecvDHCP if responding to a DHCP client, or the interface for
|
||||
// which configuration is desired if acting as a client.
|
||||
func (c *Conn) SendDHCP(pkt Packet, addr *net.UDPAddr, mac net.HardwareAddr, intf *net.Interface) error {
|
||||
func (c *Conn) SendDHCP(pkt Packet, addr *net.UDPAddr, mac net.HardwareAddr) error {
|
||||
b := pkt.Marshal()
|
||||
|
||||
ipStr, portStr, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch len(addr.IP) {
|
||||
case net.IPv4len:
|
||||
if addr.IP.Equal(net.IPv4zero) || pkt.txType() == txBroadcast {
|
||||
addr = &net.UDPAddr{IP: net.IPv4bcast, Port: addr.Port}
|
||||
}
|
||||
case net.IPv6len:
|
||||
default:
|
||||
return errors.Wrapf(errors.ErrNotSupported, "unsupported length of IP address length %d", len(addr.IP))
|
||||
|
||||
if net.ParseIP(ipStr).Equal(net.IPv4zero) || pkt.txType() == txBroadcast {
|
||||
port, _ := strconv.Atoi(portStr)
|
||||
addr = &net.UDPAddr{IP: net.IPv4bcast, Port: port}
|
||||
}
|
||||
return c.conn.Send(b, addr, mac, 0)
|
||||
|
||||
/*
|
||||
switch pkt.txType() {
|
||||
case txBroadcast, txHardwareAddr:
|
||||
addr := net.UDPAddr{
|
||||
IP: net.IPv4bcast,
|
||||
Port: dhcpClientPort,
|
||||
}
|
||||
return c.conn.Send(b, &addr, intf.Index)
|
||||
case txRelayAddr:
|
||||
addr := net.UDPAddr{
|
||||
IP: pkt.RelayAddr(),
|
||||
Port: dhcpClientPort,
|
||||
}
|
||||
log.Errorf("===============relay type pkt, addr: %#v", addr)
|
||||
return c.conn.Send(b, &addr, 0)
|
||||
case txClientAddr:
|
||||
addr := net.UDPAddr{
|
||||
IP: pkt.CIAddr(),
|
||||
Port: dhcpClientPort,
|
||||
}
|
||||
return c.conn.Send(b, &addr, 0)
|
||||
default:
|
||||
return errors.New("unknown TX type for packet")
|
||||
}*/
|
||||
return c.conn.Send(b, addr, mac)
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls. If the
|
||||
@@ -248,56 +224,6 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
type portableConn struct {
|
||||
conn *ipv4.PacketConn
|
||||
}
|
||||
|
||||
func newPortableConn(_ net.IP, port int, _ bool) (conn, error) {
|
||||
c, err := net.ListenPacket("udp4", fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l := ipv4.NewPacketConn(c)
|
||||
if err = l.SetControlMessage(ipv4.FlagInterface, true); err != nil {
|
||||
l.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &portableConn{l}, nil
|
||||
}
|
||||
|
||||
func (c *portableConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *portableConn) Recv(b []byte) (rb []byte, addr *net.UDPAddr, mac net.HardwareAddr, ifidx int, err error) {
|
||||
n, cm, a, err := c.conn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
return b[:n], a.(*net.UDPAddr), nil, cm.IfIndex, nil
|
||||
}
|
||||
|
||||
func (c *portableConn) Send(b []byte, addr *net.UDPAddr, _ net.HardwareAddr, ifidx int) error {
|
||||
if ifidx <= 0 {
|
||||
_, err := c.conn.WriteTo(b, nil, addr)
|
||||
return err
|
||||
}
|
||||
cm := ipv4.ControlMessage{
|
||||
IfIndex: ifidx,
|
||||
}
|
||||
_, err := c.conn.WriteTo(b, &cm, addr)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *portableConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *portableConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func interfaceToIPv4Addr(ifi *net.Interface) (net.IP, error) {
|
||||
if ifi == nil {
|
||||
return net.IPv4zero, nil
|
||||
@@ -318,7 +244,7 @@ func interfaceToIPv4Addr(ifi *net.Interface) (net.IP, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, errors.New("no such network interface")
|
||||
return nil, errors.Wrapf(errors.ErrNotFound, "no such network interface %s", ifi.Name)
|
||||
}
|
||||
|
||||
type socketConn struct {
|
||||
@@ -372,7 +298,7 @@ func (s *socketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
if addr, ok := a.(*syscall.SockaddrInet4); !ok {
|
||||
return nil, nil, nil, 0, errors.New("Recvfrom recevice address is not famliy Inet4")
|
||||
return nil, nil, nil, 0, errors.Wrap(errors.ErrUnsupportedProtocol, "Recvfrom recevice address is not famliy Inet4")
|
||||
} else {
|
||||
ip := net.IP{addr.Addr[0], addr.Addr[1], addr.Addr[2], addr.Addr[3]}
|
||||
udpAddr := &net.UDPAddr{
|
||||
@@ -384,7 +310,7 @@ func (s *socketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int
|
||||
}
|
||||
}
|
||||
|
||||
func (s *socketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr, ifidx int) error {
|
||||
func (s *socketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error {
|
||||
destIp := [4]byte{}
|
||||
copy(destIp[:], addr.IP.To4()[:4])
|
||||
destAddr := &syscall.SockaddrInet4{
|
||||
@@ -395,9 +321,9 @@ func (s *socketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr,
|
||||
}
|
||||
|
||||
func (s *socketConn) SetReadDeadline(t time.Time) error {
|
||||
return errors.New("Not Implement")
|
||||
return errors.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (s *socketConn) SetWriteDeadline(t time.Time) error {
|
||||
return errors.New("Not Implement")
|
||||
return errors.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
// 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.
|
||||
|
||||
// Copyright 2019 Yunion
|
||||
// Copyright 2016 Google Inc.
|
||||
//
|
||||
// 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 dhcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
// defined as a var so tests can override it.
|
||||
var (
|
||||
dhcpv6ClientPort = 546
|
||||
)
|
||||
|
||||
func NewRawSocketConn6(iface string, filter []bpf.RawInstruction, serverPort uint16) (*Conn, error) {
|
||||
conn, err := newRawSocketConn6(iface, filter, serverPort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Conn{conn, 0}, nil
|
||||
}
|
||||
|
||||
func NewSocketConn6(addr string, port int) (*Conn, error) {
|
||||
conn, err := newSocketConn6(net.ParseIP(addr), port, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Conn{conn, 0}, nil
|
||||
}
|
||||
|
||||
func interfaceToIPv6Addr(ifi *net.Interface) (net.IP, error) {
|
||||
if ifi == nil {
|
||||
return net.IPv6zero, nil
|
||||
}
|
||||
ifat, err := ifi.Addrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, ifa := range ifat {
|
||||
switch v := ifa.(type) {
|
||||
case *net.IPAddr:
|
||||
if len(v.IP) == net.IPv6len {
|
||||
return v.IP, nil
|
||||
}
|
||||
case *net.IPNet:
|
||||
if len(v.IP) == net.IPv6len {
|
||||
return v.IP, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, errors.Wrapf(errors.ErrNotFound, "no such network interface %s", ifi.Name)
|
||||
}
|
||||
|
||||
func newSocketConn6(addr net.IP, port int, disableBroadcast bool) (conn, error) {
|
||||
var broadcastOpt = 1
|
||||
if disableBroadcast {
|
||||
broadcastOpt = 0
|
||||
}
|
||||
sock, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = syscall.SetsockoptInt(sock, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = syscall.SetsockoptInt(sock, syscall.SOL_SOCKET, syscall.SO_BROADCAST, broadcastOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byteAddr := [16]byte{}
|
||||
copy(byteAddr[:], addr.To16())
|
||||
lsa := &syscall.SockaddrInet6{
|
||||
Port: port,
|
||||
Addr: byteAddr,
|
||||
}
|
||||
if err = syscall.Bind(sock, lsa); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = syscall.SetNonblock(sock, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Its equal syscall.CloseOnExec
|
||||
// most file descriptors are getting set to close-on-exec
|
||||
// apart from syscall open, socket etc.
|
||||
syscall.Syscall(syscall.SYS_FCNTL, uintptr(sock), syscall.F_SETFD, syscall.FD_CLOEXEC)
|
||||
return &socketConn{sock}, nil
|
||||
}
|
||||
|
||||
func (s *socketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error) {
|
||||
n, a, err := syscall.Recvfrom(s.sock, b, 0)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
if addr, ok := a.(*syscall.SockaddrInet6); !ok {
|
||||
return nil, nil, nil, 0, errors.Wrap(errors.ErrUnsupportedProtocol, "Recvfrom recevice address is not famliy Inet6")
|
||||
} else {
|
||||
ip := net.IP(addr.Addr[:])
|
||||
udpAddr := &net.UDPAddr{
|
||||
IP: ip,
|
||||
Port: addr.Port,
|
||||
}
|
||||
// there is no interface index info
|
||||
return b[:n], udpAddr, nil, 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *socketConn) Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error {
|
||||
destIp := [16]byte{}
|
||||
copy(destIp[:], addr.IP.To16())
|
||||
destAddr := &syscall.SockaddrInet6{
|
||||
Addr: destIp,
|
||||
Port: addr.Port,
|
||||
}
|
||||
return syscall.Sendto(s.sock, b, 0, destAddr)
|
||||
}
|
||||
+31
-131
@@ -33,7 +33,6 @@
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@@ -41,21 +40,22 @@ import (
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/mdlayher/packet"
|
||||
"golang.org/x/net/bpf"
|
||||
"golang.org/x/net/ipv4"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
type rawSocketConn struct {
|
||||
conn *packet.Conn
|
||||
|
||||
iface *net.Interface
|
||||
ip net.IP
|
||||
dhcpServerPort uint16
|
||||
iface *net.Interface
|
||||
ip net.IP
|
||||
|
||||
serverPort uint16
|
||||
}
|
||||
|
||||
func newRawSocketConn(iface string, filter []bpf.RawInstruction, dhcpServerPort uint16) (conn, error) {
|
||||
func newRawSocketConn(iface string, filter []bpf.RawInstruction, serverPort uint16) (conn, error) {
|
||||
ifi, err := net.InterfaceByName(iface)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "interface by name")
|
||||
@@ -63,18 +63,24 @@ func newRawSocketConn(iface string, filter []bpf.RawInstruction, dhcpServerPort
|
||||
|
||||
ip, err := interfaceToIPv4Addr(ifi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "interfaceToIPv4Addr")
|
||||
}
|
||||
|
||||
// unix.ETH_P_ALL
|
||||
conn, err := packet.Listen(ifi, packet.Raw, unix.ETH_P_IP, &packet.Config{
|
||||
// NoCumulativeStats: true,
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "packet.Listen")
|
||||
}
|
||||
return &rawSocketConn{conn, ifi, ip, dhcpServerPort}, nil
|
||||
log.Debugf("newRawSocketConn on %s %s", ifi.Name, ip)
|
||||
|
||||
return &rawSocketConn{
|
||||
conn: conn,
|
||||
iface: ifi,
|
||||
ip: ip,
|
||||
serverPort: serverPort,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) Close() error {
|
||||
@@ -87,6 +93,8 @@ func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Read from errror")
|
||||
}
|
||||
log.Debugf("rawSocketConn Recv %d bytes", n)
|
||||
|
||||
b = b[:n]
|
||||
|
||||
srcMac, err := net.ParseMAC(addr.String())
|
||||
@@ -100,12 +108,15 @@ func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
}
|
||||
|
||||
var srcIp net.IP
|
||||
ipLayer := p.Layer(layers.LayerTypeIPv4)
|
||||
if ipLayer != nil {
|
||||
ip4 := ipLayer.(*layers.IPv4)
|
||||
srcIp = ip4.SrcIP
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Fetch ip layer failed")
|
||||
{
|
||||
ipLayer := p.Layer(layers.LayerTypeIPv4)
|
||||
if ipLayer != nil {
|
||||
// ipv4
|
||||
ip4 := ipLayer.(*layers.IPv4)
|
||||
srcIp = ip4.SrcIP
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Expect IP packet")
|
||||
}
|
||||
}
|
||||
|
||||
var srcPort uint16
|
||||
@@ -114,11 +125,12 @@ func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
udpInfo := udpLayer.(*layers.UDP)
|
||||
srcPort = uint16(udpInfo.SrcPort)
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Fetch upd layer failed")
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Expect UDP packet")
|
||||
}
|
||||
|
||||
dhcpLayer := p.Layer(layers.LayerTypeDHCPv4)
|
||||
if dhcpLayer != nil {
|
||||
// dhcpv4
|
||||
dhcp4 := dhcpLayer.(*layers.DHCPv4)
|
||||
sbf := gopacket.NewSerializeBuffer()
|
||||
if err := dhcp4.SerializeTo(sbf, gopacket.SerializeOptions{}); err != nil {
|
||||
@@ -126,11 +138,11 @@ func (s *rawSocketConn) Recv(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr,
|
||||
}
|
||||
return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: int(srcPort)}, srcMac, 0, nil
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Fetch dhcp layer failed")
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Expect DHCP packet")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr, ifidx int) error {
|
||||
func (s *rawSocketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error {
|
||||
var dhcp = new(layers.DHCPv4)
|
||||
if err := dhcp.DecodeFromBytes(b, gopacket.NilDecodeFeedback); err != nil {
|
||||
return errors.Wrap(err, "Decode dhcp bytes error")
|
||||
@@ -151,7 +163,7 @@ func (s *rawSocketConn) Send(b []byte, addr *net.UDPAddr, destMac net.HardwareAd
|
||||
}
|
||||
|
||||
var (
|
||||
srcPort = layers.UDPPort(s.dhcpServerPort)
|
||||
srcPort = layers.UDPPort(s.serverPort)
|
||||
dstPort = layers.UDPPort(addr.Port)
|
||||
)
|
||||
|
||||
@@ -183,115 +195,3 @@ func (s *rawSocketConn) SetReadDeadline(t time.Time) error {
|
||||
func (s *rawSocketConn) SetWriteDeadline(t time.Time) error {
|
||||
return s.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
type linuxConn struct {
|
||||
port uint16
|
||||
conn *ipv4.RawConn
|
||||
}
|
||||
|
||||
// NewSnooperConn creates a Conn that listens on the given UDP ip:port.
|
||||
//
|
||||
// Unlike NewConn, NewSnooperConn does not bind to the ip:port,
|
||||
// enabling the Conn to coexist with other services on the machine.
|
||||
func NewSnooperConn(addr string) (*Conn, error) {
|
||||
return newConn(addr, false, newLinuxConn)
|
||||
}
|
||||
|
||||
func newLinuxConn(_ net.IP, port int, disableBroadcast bool) (conn, error) {
|
||||
if port == 0 {
|
||||
return nil, errors.Error("must specify a listen port")
|
||||
}
|
||||
|
||||
filter, err := bpf.Assemble([]bpf.Instruction{
|
||||
// Load IPv4 packet length
|
||||
bpf.LoadMemShift{Off: 0},
|
||||
// Get UDP dport
|
||||
bpf.LoadIndirect{Off: 2, Size: 2},
|
||||
// Correct dport?
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(port), SkipFalse: 1},
|
||||
// Accept
|
||||
bpf.RetConstant{Val: 1500},
|
||||
// Ignore
|
||||
bpf.RetConstant{Val: 0},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := net.ListenPacket("ip4:17", "0.0.0.0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := ipv4.NewRawConn(c)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err = r.SetControlMessage(ipv4.FlagInterface, true); err != nil {
|
||||
c.Close()
|
||||
return nil, errors.Wrap(err, "setting packet filter")
|
||||
}
|
||||
if err = r.SetBPF(filter); err != nil {
|
||||
c.Close()
|
||||
return nil, errors.Wrap(err, "setting packet filter")
|
||||
}
|
||||
|
||||
ret := &linuxConn{
|
||||
port: uint16(port),
|
||||
conn: r,
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *linuxConn) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *linuxConn) Recv(b []byte) (rb []byte, addr *net.UDPAddr, mac net.HardwareAddr, ifidx int, err error) {
|
||||
hdr, p, cm, err := c.conn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, err
|
||||
}
|
||||
if len(p) < 8 {
|
||||
return nil, nil, nil, 0, errors.Error("not a UDP packet, too short")
|
||||
}
|
||||
sport := int(binary.BigEndian.Uint16(p[:2]))
|
||||
return p[8:], &net.UDPAddr{IP: hdr.Src, Port: sport}, nil, cm.IfIndex, nil
|
||||
}
|
||||
|
||||
func (c *linuxConn) Send(b []byte, addr *net.UDPAddr, _ net.HardwareAddr, ifidx int) error {
|
||||
packet := make([]byte, 8+len(b))
|
||||
// src port
|
||||
binary.BigEndian.PutUint16(packet[:2], c.port)
|
||||
// dst port
|
||||
binary.BigEndian.PutUint16(packet[2:4], uint16(addr.Port))
|
||||
// length
|
||||
binary.BigEndian.PutUint16(packet[4:6], uint16(8+len(b)))
|
||||
copy(packet[8:], b)
|
||||
|
||||
hdr := ipv4.Header{
|
||||
Version: 4,
|
||||
Len: ipv4.HeaderLen,
|
||||
TOS: 0xc0, // DSCP CS6 (Network Control)
|
||||
TotalLen: ipv4.HeaderLen + 8 + len(b),
|
||||
TTL: 64,
|
||||
Protocol: 17,
|
||||
Dst: addr.IP,
|
||||
}
|
||||
|
||||
if ifidx > 0 {
|
||||
cm := ipv4.ControlMessage{
|
||||
IfIndex: ifidx,
|
||||
}
|
||||
return c.conn.WriteTo(&hdr, packet, &cm)
|
||||
}
|
||||
return c.conn.WriteTo(&hdr, packet, nil)
|
||||
}
|
||||
|
||||
func (c *linuxConn) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *linuxConn) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
// 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.
|
||||
|
||||
// Copyright 2019 Yunion
|
||||
// Copyright 2016 Google Inc.
|
||||
//
|
||||
// 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.
|
||||
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/mdlayher/packet"
|
||||
"golang.org/x/net/bpf"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
func newRawSocketConn6(iface string, filter []bpf.RawInstruction, serverPort uint16) (conn, error) {
|
||||
ifi, err := net.InterfaceByName(iface)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "interface by name")
|
||||
}
|
||||
|
||||
ip, err := interfaceToIPv6Addr(ifi)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "interfaceToIPv6Addr")
|
||||
}
|
||||
|
||||
// unix.ETH_P_ALL
|
||||
conn, err := packet.Listen(ifi, packet.Raw, unix.ETH_P_IPV6, &packet.Config{
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "packet.Listen")
|
||||
}
|
||||
log.Debugf("newRawSocketConn6 on %s %s", ifi.Name, ip)
|
||||
return &rawSocketConn{
|
||||
conn: conn,
|
||||
iface: ifi,
|
||||
ip: ip,
|
||||
serverPort: serverPort,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) Recv6(b []byte) ([]byte, *net.UDPAddr, net.HardwareAddr, int, error) {
|
||||
// read packet
|
||||
n, addr, err := s.conn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Read from errror")
|
||||
}
|
||||
log.Debugf("rawSocketConn Recv6 %d bytes from %s", n, addr.String())
|
||||
|
||||
b = b[:n]
|
||||
|
||||
srcMac, err := net.ParseMAC(addr.String())
|
||||
if err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Parse mac error")
|
||||
}
|
||||
|
||||
p := gopacket.NewPacket(b, layers.LayerTypeEthernet, gopacket.Default)
|
||||
if p.ErrorLayer() != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Failed to decode packet")
|
||||
}
|
||||
|
||||
var srcIp net.IP
|
||||
{
|
||||
ipLayer := p.Layer(layers.LayerTypeIPv6)
|
||||
if ipLayer != nil {
|
||||
// ipv6
|
||||
ip6 := ipLayer.(*layers.IPv6)
|
||||
srcIp = ip6.SrcIP
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Expect IPv6 packet")
|
||||
}
|
||||
}
|
||||
|
||||
icmpLayer := p.Layer(layers.LayerTypeICMPv6)
|
||||
if icmpLayer != nil {
|
||||
raLayer := p.Layer(layers.LayerTypeICMPv6RouterSolicitation)
|
||||
if raLayer != nil {
|
||||
// icmp6, ra solitation
|
||||
raPkt := raLayer.(*layers.ICMPv6RouterSolicitation)
|
||||
sbf := gopacket.NewSerializeBuffer()
|
||||
if err := raPkt.SerializeTo(sbf, gopacket.SerializeOptions{}); err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Serialize ICMPv6 ra solitation packet error")
|
||||
}
|
||||
return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: icmpRAFakePort}, srcMac, 0, nil
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "expect an ICMPv6 RA solitation packet")
|
||||
}
|
||||
}
|
||||
|
||||
var srcPort uint16
|
||||
udpLayer := p.Layer(layers.LayerTypeUDP)
|
||||
if udpLayer != nil {
|
||||
udpInfo := udpLayer.(*layers.UDP)
|
||||
srcPort = uint16(udpInfo.SrcPort)
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "expect UDP packet")
|
||||
}
|
||||
|
||||
dhcpLayer := p.Layer(layers.LayerTypeDHCPv6)
|
||||
if dhcpLayer != nil {
|
||||
// dhcpv6
|
||||
dhcp6 := dhcpLayer.(*layers.DHCPv6)
|
||||
sbf := gopacket.NewSerializeBuffer()
|
||||
if err := dhcp6.SerializeTo(sbf, gopacket.SerializeOptions{}); err != nil {
|
||||
return nil, nil, nil, 0, errors.Wrap(err, "Serialize dhcp6 packet error")
|
||||
}
|
||||
return sbf.Bytes(), &net.UDPAddr{IP: srcIp, Port: int(srcPort)}, srcMac, 0, nil
|
||||
} else {
|
||||
return nil, nil, nil, 0, errors.Wrap(p.ErrorLayer().Error(), "Fetch dhcp layer failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *rawSocketConn) Send6(b []byte, addr *net.UDPAddr, destMac net.HardwareAddr) error {
|
||||
var dhcp = new(layers.DHCPv4)
|
||||
if err := dhcp.DecodeFromBytes(b, gopacket.NilDecodeFeedback); err != nil {
|
||||
return errors.Wrap(err, "Decode dhcp bytes error")
|
||||
}
|
||||
|
||||
var eth = &layers.Ethernet{
|
||||
EthernetType: layers.EthernetTypeIPv4,
|
||||
SrcMAC: s.iface.HardwareAddr,
|
||||
DstMAC: destMac,
|
||||
}
|
||||
|
||||
var ip = &layers.IPv6{
|
||||
Version: 6,
|
||||
HopLimit: 64,
|
||||
SrcIP: s.ip,
|
||||
DstIP: addr.IP,
|
||||
NextHeader: layers.IPProtocolUDP,
|
||||
}
|
||||
|
||||
var (
|
||||
srcPort = layers.UDPPort(s.serverPort)
|
||||
dstPort = layers.UDPPort(addr.Port)
|
||||
)
|
||||
|
||||
var udp = &layers.UDP{
|
||||
SrcPort: srcPort,
|
||||
DstPort: dstPort,
|
||||
}
|
||||
udp.SetNetworkLayerForChecksum(ip)
|
||||
|
||||
var (
|
||||
buf = gopacket.NewSerializeBuffer()
|
||||
opts = gopacket.SerializeOptions{ComputeChecksums: true, FixLengths: true}
|
||||
)
|
||||
if err := gopacket.SerializeLayers(buf, opts, eth, ip, udp, dhcp); 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 dhcp packet error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -49,3 +49,7 @@ func NewSnooperConn(addr string) (*Conn, error) {
|
||||
func newRawSocketConn(iface string, filter []bpf.RawInstruction, dhcpServerPort uint16) (conn, error) {
|
||||
return nil, errors.New("raw socket Conns not supported on this OS")
|
||||
}
|
||||
|
||||
func newRawSocketConn6(iface string, filter []bpf.RawInstruction, dhcpServerPort uint16) (conn, error) {
|
||||
return nil, errors.New("raw IPv6 socket Conns not supported on this OS")
|
||||
}
|
||||
|
||||
@@ -44,6 +44,10 @@ const (
|
||||
CLIENT_ARCH_EFI_ARM64
|
||||
)
|
||||
|
||||
const (
|
||||
icmpRAFakePort = int(-1111)
|
||||
)
|
||||
|
||||
func IsUEFIPxeArch(arch uint16) bool {
|
||||
switch arch {
|
||||
case CLIENT_ARCH_EFI_IA32:
|
||||
|
||||
@@ -49,6 +49,10 @@ type ResponseConfig struct {
|
||||
NTPServers []net.IP // OptNTPServers 42
|
||||
MTU uint16 // OptMTU 26
|
||||
|
||||
ClientIP6 net.IP
|
||||
Gateway6 net.IP
|
||||
PrefixLen6 uint8
|
||||
|
||||
// Relay Info https://datatracker.ietf.org/doc/html/rfc3046
|
||||
RelayInfo []byte
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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 dhcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type DHCPHandler interface {
|
||||
ServeDHCP(pkt Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (Packet, []string, error)
|
||||
}
|
||||
|
||||
type DHCP6Handler interface {
|
||||
DHCPHandler
|
||||
|
||||
ServeRA(pkt Packet, cliMac net.HardwareAddr, addr *net.UDPAddr) (Packet, error)
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
// 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 dhcp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
)
|
||||
|
||||
type icmpV6OptMtu struct {
|
||||
MTU uint32
|
||||
}
|
||||
|
||||
func (opt icmpV6OptMtu) Bytes() []byte {
|
||||
buf := make([]byte, 6)
|
||||
binary.BigEndian.PutUint32(buf[2:], opt.MTU)
|
||||
return buf
|
||||
}
|
||||
|
||||
func NewIcmpV6OptMtu(mtu uint32) icmpV6OptMtu {
|
||||
return icmpV6OptMtu{
|
||||
MTU: mtu,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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 |L|A| Reserved1 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Valid Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Preferred Lifetime |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Reserved2 |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+ Prefix +
|
||||
| |
|
||||
+ +
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
type icmpv6OptPrefixInfo struct {
|
||||
PrefixLen uint8
|
||||
Flag uint8
|
||||
ValidLifetime uint32
|
||||
PreferredLifetime uint32
|
||||
Reserved2 uint32
|
||||
Prefix [16]byte
|
||||
}
|
||||
|
||||
func (opt icmpv6OptPrefixInfo) Bytes() []byte {
|
||||
buf := make([]byte, 30)
|
||||
buf[0] = opt.PrefixLen
|
||||
buf[1] = opt.Flag
|
||||
binary.BigEndian.PutUint32(buf[2:], opt.ValidLifetime)
|
||||
binary.BigEndian.PutUint32(buf[6:], opt.PreferredLifetime)
|
||||
binary.BigEndian.PutUint32(buf[10:], opt.Reserved2)
|
||||
copy(buf[14:], opt.Prefix[:])
|
||||
return buf
|
||||
}
|
||||
|
||||
func NewIcmpv6OptPrefixInfo(gw net.IP, preflen uint8) icmpv6OptPrefixInfo {
|
||||
return icmpv6OptPrefixInfo{
|
||||
PrefixLen: preflen,
|
||||
Flag: 0x80,
|
||||
ValidLifetime: 0xffffffff,
|
||||
PreferredLifetime: 0xffffffff,
|
||||
Reserved2: 0,
|
||||
Prefix: [16]byte(gw),
|
||||
}
|
||||
}
|
||||
|
||||
type icmpv6OptSourceTargetAddress struct {
|
||||
Mac netutils.SMacAddr
|
||||
}
|
||||
|
||||
func (opt icmpv6OptSourceTargetAddress) Bytes() []byte {
|
||||
return opt.Mac[:]
|
||||
}
|
||||
|
||||
func NewIcmpv6OptSourceTargetAddress(macAddr string) icmpv6OptSourceTargetAddress {
|
||||
mac, _ := netutils.ParseMac(macAddr)
|
||||
return icmpv6OptSourceTargetAddress{
|
||||
Mac: mac,
|
||||
}
|
||||
}
|
||||
|
||||
func MakeRouterAdverPacket(gwIP net.IP, preflen uint8, mtu uint32) (Packet, error) {
|
||||
pkt := layers.ICMPv6RouterAdvertisement{}
|
||||
pkt.Flags = 0x80 // M=1, O=0 stateful DHCPv6
|
||||
|
||||
pkt.Options = layers.ICMPv6Options{
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptMTU,
|
||||
Data: NewIcmpV6OptMtu(mtu).Bytes(),
|
||||
},
|
||||
layers.ICMPv6Option{
|
||||
Type: layers.ICMPv6OptPrefixInfo,
|
||||
Data: NewIcmpv6OptPrefixInfo(gwIP, preflen).Bytes(),
|
||||
},
|
||||
}
|
||||
|
||||
sbf := gopacket.NewSerializeBuffer()
|
||||
err := pkt.SerializeTo(sbf, gopacket.SerializeOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SerializeTo")
|
||||
}
|
||||
return sbf.Bytes(), nil
|
||||
}
|
||||
|
||||
// DHCPv6 https://datatracker.ietf.org/doc/html/rfc8415
|
||||
/*
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| msg-type | transaction-id |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| |
|
||||
. options .
|
||||
. (variable number and length) .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
/*
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| msg-type | hop-count | |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
||||
| |
|
||||
| link-address |
|
||||
| |
|
||||
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
|
||||
| | |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
||||
| |
|
||||
| peer-address |
|
||||
| |
|
||||
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
|
||||
| | |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
||||
. .
|
||||
. options (variable number and length) .... .
|
||||
| |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
|
||||
// DHCPv6 Message Type
|
||||
const (
|
||||
DHCPV6_SOLICIT MessageType = 1
|
||||
DHCPV6_ADVERTISE MessageType = 2
|
||||
DHCPV6_REQUEST MessageType = 3
|
||||
DHCPV6_CONFIRM MessageType = 4
|
||||
DHCPV6_RENEW MessageType = 5
|
||||
DHCPV6_REBIND MessageType = 6
|
||||
DHCPV6_REPLY MessageType = 7
|
||||
DHCPV6_RELEASE MessageType = 8
|
||||
DHCPV6_DECLINE MessageType = 9
|
||||
DHCPV6_RECONFIGURE MessageType = 10
|
||||
DHCPV6_INFORMATION_REQUEST MessageType = 11
|
||||
DHCPV6_RELAY_FORW MessageType = 12
|
||||
DHCPV6_RELAY_REPL MessageType = 13
|
||||
)
|
||||
|
||||
type OptionCode6 uint16
|
||||
|
||||
const (
|
||||
DHCPV6_OPTION_CLIENTID OptionCode6 = 1
|
||||
DHCPV6_OPTION_SERVERID OptionCode6 = 2
|
||||
DHCPV6_OPTION_IA_NA OptionCode6 = 3
|
||||
DHCPV6_OPTION_IA_TA OptionCode6 = 4
|
||||
DHCPV6_OPTION_IAADDR OptionCode6 = 5
|
||||
DHCPV6_OPTION_ORO OptionCode6 = 6
|
||||
DHCPV6_OPTION_PREFERENCE OptionCode6 = 7
|
||||
DHCPV6_OPTION_ELAPSED_TIME OptionCode6 = 8
|
||||
DHCPV6_OPTION_RELAY_MSG OptionCode6 = 9
|
||||
DHCPV6_OPTION_AUTH OptionCode6 = 11
|
||||
DHCPV6_OPTION_UNICAST OptionCode6 = 12
|
||||
DHCPV6_OPTION_STATUS_CODE OptionCode6 = 13
|
||||
DHCPV6_OPTION_RAPID_COMMIT OptionCode6 = 14
|
||||
DHCPV6_OPTION_USER_CLASS OptionCode6 = 15
|
||||
DHCPV6_OPTION_VENDOR_CLASS OptionCode6 = 16
|
||||
DHCPV6_OPTION_VENDOR_OPTS OptionCode6 = 17
|
||||
DHCPV6_OPTION_INTERFACE_ID OptionCode6 = 18
|
||||
DHCPV6_OPTION_RECONF_MSG OptionCode6 = 19
|
||||
DHCPV6_OPTION_RECONF_ACCEPT OptionCode6 = 20
|
||||
DHCPV6_OPTION_IA_PD OptionCode6 = 25
|
||||
DHCPV6_OPTION_IAPREFIX OptionCode6 = 26
|
||||
DHCPV6_OPTION_INFORMATION_REFRESH_TIME OptionCode6 = 32
|
||||
DHCPV6_OPTION_SOL_MAX_RT OptionCode6 = 82
|
||||
DHCPV6_OPTION_INF_MAX_RT OptionCode6 = 83
|
||||
)
|
||||
|
||||
// DHCPv6 message type
|
||||
func (p Packet) Type6() MessageType {
|
||||
return MessageType(p[0])
|
||||
}
|
||||
|
||||
// DHCPv6 transaction ID
|
||||
func (p Packet) TID() uint32 {
|
||||
return binary.BigEndian.Uint32([]byte{0, p[1], p[2], p[3]})
|
||||
}
|
||||
|
||||
// DHCPv6 hop Count for relay message
|
||||
func (p Packet) HopCount() byte {
|
||||
return p[1]
|
||||
}
|
||||
|
||||
// DHCPv6 link address for relay message
|
||||
func (p Packet) LinkAddr() net.IP {
|
||||
return net.IP(p[2:18])
|
||||
}
|
||||
|
||||
// DHCPv6 peer address for relay message
|
||||
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) SetTID(tid uint32) {
|
||||
tidBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(tidBytes, tid)
|
||||
p[1] = tidBytes[1]
|
||||
p[2] = tidBytes[2]
|
||||
p[3] = tidBytes[3]
|
||||
}
|
||||
|
||||
func (p Packet) SetHopCount(hops byte) {
|
||||
p[1] = hops
|
||||
}
|
||||
|
||||
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 NewPacket6(opCode MessageType, tid uint32) Packet {
|
||||
p := make(Packet, 4)
|
||||
p.SetType6(opCode)
|
||||
p.SetTID(tid)
|
||||
return p
|
||||
}
|
||||
|
||||
type Option6 struct {
|
||||
Code OptionCode6
|
||||
Value []byte
|
||||
}
|
||||
|
||||
// Appends a DHCP option to the end of a packet
|
||||
/*
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| option-code | option-len |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| option-data |
|
||||
| (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...)
|
||||
}
|
||||
|
||||
// Creates a request packet that a Client would send to a server.
|
||||
func RequestPacket6(mt MessageType, tid uint32, options []Option6) Packet {
|
||||
p := NewPacket6(mt, tid)
|
||||
for _, o := range options {
|
||||
p.AddOption6(o)
|
||||
}
|
||||
return p
|
||||
}
|
||||
+225
-44
@@ -15,14 +15,13 @@
|
||||
package dhcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
|
||||
"golang.org/x/net/bpf"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
type DHCPServer struct {
|
||||
@@ -31,25 +30,15 @@ type DHCPServer struct {
|
||||
conn *Conn
|
||||
}
|
||||
|
||||
// net.ListenPacket
|
||||
func NewDHCPServer(address string, port int) (*DHCPServer, error) {
|
||||
dhcpAddr := fmt.Sprintf("%s:%d", address, port)
|
||||
dhcpConn, err := NewConn(dhcpAddr, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("New DHCP connection error: %v", err)
|
||||
}
|
||||
return &DHCPServer{
|
||||
Address: address,
|
||||
Port: port,
|
||||
conn: dhcpConn,
|
||||
}, nil
|
||||
type DHCP6Server struct {
|
||||
DHCPServer
|
||||
}
|
||||
|
||||
// udp socket
|
||||
// udp unicast socket
|
||||
func NewDHCPServer3(address string, port int) (*DHCPServer, error) {
|
||||
dhcpConn, err := NewSocketConn(address, port)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("New DHCP connection error: %v", err)
|
||||
return nil, errors.Wrap(err, "New DHCP connection")
|
||||
}
|
||||
return &DHCPServer{
|
||||
Address: address,
|
||||
@@ -58,28 +47,137 @@ func NewDHCPServer3(address string, port int) (*DHCPServer, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// raw socket
|
||||
func NewDHCPServer2(iface string, dhcpServerPort, dhcpRelayPort uint16) (*DHCPServer, *Conn, error) {
|
||||
// ip and udp and port 67 and port 68
|
||||
bpf := []bpf.RawInstruction{
|
||||
{Op: 0x28, Jt: 0, Jf: 0, K: 0x0000000c},
|
||||
{Op: 0x15, Jt: 0, Jf: 13, K: 0x00000800},
|
||||
{Op: 0x30, Jt: 0, Jf: 0, K: 0x00000017},
|
||||
{Op: 0x15, Jt: 0, Jf: 11, K: 0x00000011},
|
||||
{Op: 0x28, Jt: 0, Jf: 0, K: 0x00000014},
|
||||
{Op: 0x45, Jt: 9, Jf: 0, K: 0x00001fff},
|
||||
{Op: 0xb1, Jt: 0, Jf: 0, K: 0x0000000e},
|
||||
{Op: 0x48, Jt: 0, Jf: 0, K: 0x0000000e},
|
||||
{Op: 0x15, Jt: 0, Jf: 2, K: uint32(dhcpServerPort)},
|
||||
{Op: 0x48, Jt: 0, Jf: 0, K: 0x00000010},
|
||||
{Op: 0x15, Jt: 3, Jf: 4, K: uint32(dhcpRelayPort)},
|
||||
{Op: 0x15, Jt: 0, Jf: 3, K: uint32(dhcpRelayPort)},
|
||||
{Op: 0x48, Jt: 0, Jf: 0, K: 0x00000010},
|
||||
{Op: 0x15, Jt: 0, Jf: 1, K: uint32(dhcpServerPort)},
|
||||
{Op: 0x6, Jt: 0, Jf: 0, K: 0x00040000},
|
||||
{Op: 0x6, Jt: 0, Jf: 0, K: 0x00000000},
|
||||
// udp unicast socket
|
||||
func NewDHCP6Server3(address string, port int) (*DHCP6Server, error) {
|
||||
dhcpConn, err := NewSocketConn(address, port)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "New DHCP6 connection")
|
||||
}
|
||||
conn, err := NewRawSocketConn(iface, bpf, dhcpServerPort)
|
||||
return &DHCP6Server{
|
||||
DHCPServer{
|
||||
Address: address,
|
||||
Port: port,
|
||||
conn: dhcpConn,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
const (
|
||||
bpfContinue uint8 = 0
|
||||
bpfProcDhcpResp uint8 = 11
|
||||
|
||||
bpfProcDhcpResp6 uint8 = 8
|
||||
bpfProcICMPv6 uint8 = 11
|
||||
bpfProcReadPkt6 uint8 = 14
|
||||
bpfProcEnd6 uint8 = 15
|
||||
|
||||
bpfProcReadPkt4 uint8 = 14
|
||||
bpfProcEnd4 uint8 = 15
|
||||
|
||||
udpProtocol uint32 = 17
|
||||
icmpProtocol uint32 = 58
|
||||
)
|
||||
|
||||
var (
|
||||
v4bpf = []bpf.Instruction{
|
||||
/* 0 load ethernet type, 2bytes */
|
||||
&bpf.LoadAbsolute{Off: 12, Size: 2},
|
||||
|
||||
/* 1 if ether_type != 0x0800(IPv4) then jump to [end] else continue */
|
||||
&bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0800, SkipTrue: bpfGoto(2, bpfProcEnd4), SkipFalse: bpfContinue},
|
||||
/* 2 load ipv4 protocol, offset 23, 1 byte */
|
||||
&bpf.LoadAbsolute{Off: 23, Size: 1},
|
||||
/* 3 if ip_proto != UDP then jump to [end] else continue */
|
||||
&bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: udpProtocol, SkipTrue: bpfGoto(4, bpfProcEnd4), SkipFalse: bpfContinue},
|
||||
/* 4 if load ip flags & fragment_offset */
|
||||
&bpf.LoadAbsolute{Off: 20, Size: 2},
|
||||
/* 5 if ip_fragment_offset != 0 then jump to end/25(6+19) else continue */
|
||||
bpf.JumpIf{Cond: bpf.JumpBitsSet, Val: 0x1fff, SkipTrue: bpfGoto(6, bpfProcEnd4), SkipFalse: bpfContinue},
|
||||
/* 6 store ip_header_length*4 in register X */
|
||||
bpf.LoadMemShift{Off: 14},
|
||||
/* 7 load 14 + ip_header_len + 0 (UDP src port), 2 bytes */
|
||||
bpf.LoadIndirect{Off: 14, Size: 2},
|
||||
/* 8 if udp_src_port != 67 then jump to dhcp_resp/11(9+2) else continue */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 67, SkipTrue: bpfGoto(9, bpfProcDhcpResp), SkipFalse: bpfContinue},
|
||||
/* 9 load 14 + ip_header_len + 2 (udp dst port), 2 bytes */
|
||||
bpf.LoadIndirect{Off: 16, Size: 2},
|
||||
/* 10 if udp_dst_port == 68 then jump to read/24(11+13) else jump to end/25(11+14) */
|
||||
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 68, SkipTrue: bpfGoto(11, bpfProcReadPkt4), SkipFalse: bpfGoto(11, bpfProcEnd4)},
|
||||
/* 11 [dhcp_resp] if udp_src_port != 68 then jump to end/25(12+13) else continue, which means a UDP response */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 68, SkipTrue: bpfGoto(12, bpfProcEnd4), SkipFalse: bpfContinue},
|
||||
/* 12 load 14 + ip_header_len + 2 (udp dst port), 2 bytes */
|
||||
bpf.LoadIndirect{Off: 16, Size: 2},
|
||||
/* 13 if udp_dst_port != 67 then jump to end/25(14+11) else continue */
|
||||
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 67, SkipTrue: bpfGoto(14, bpfProcEnd4), SkipFalse: bpfContinue},
|
||||
|
||||
/* 14 [read] return the whole packet */
|
||||
bpf.RetConstant{Val: 0x40000},
|
||||
/* 15 [end] return none */
|
||||
bpf.RetConstant{Val: 0x0},
|
||||
}
|
||||
|
||||
v6bpf = []bpf.Instruction{
|
||||
/* 0 load ethernet type, 2bytes */
|
||||
&bpf.LoadAbsolute{Off: 12, Size: 2},
|
||||
|
||||
/* 1 [ipv6] if ether_type != 0x86dd(IPv6) then jump to end/25(15 + 10) else continue */
|
||||
&bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x86dd, SkipTrue: bpfGoto(2, bpfProcEnd6), SkipFalse: bpfContinue},
|
||||
/* 2 load ipv6 next header, offset 20, 1 byte */
|
||||
&bpf.LoadAbsolute{Off: 20, Size: 1},
|
||||
/* 3 [udp6] if ip_proto != UDP then jump to [icmp6]/24(17 + 7) else continue */
|
||||
&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},
|
||||
/* 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},
|
||||
/* 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)},
|
||||
|
||||
/* 11 [icmp6] if ip_proto != ICMP then jump to [end]/24(17 + 7) 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)},
|
||||
|
||||
/* 14 [read] return the whole packet */
|
||||
bpf.RetConstant{Val: 0x40000},
|
||||
/* 15 [end] return none */
|
||||
bpf.RetConstant{Val: 0x0},
|
||||
}
|
||||
)
|
||||
|
||||
func bpfGoto(current uint8, jumpTo uint8) uint8 {
|
||||
return jumpTo - current
|
||||
}
|
||||
|
||||
func getRawInstructions(obpf []bpf.Instruction) ([]bpf.RawInstruction, error) {
|
||||
bpf := make([]bpf.RawInstruction, 0, len(obpf))
|
||||
for i := range obpf {
|
||||
inst, err := obpf[i].Assemble()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "invalid eBPF instruction")
|
||||
}
|
||||
bpf = append(bpf, inst)
|
||||
}
|
||||
return bpf, nil
|
||||
}
|
||||
|
||||
// raw socket
|
||||
func NewDHCPServer2(iface string, port uint16) (*DHCPServer, *Conn, error) {
|
||||
bpf, err := getRawInstructions(v4bpf)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "getRawInstructions")
|
||||
}
|
||||
conn, err := NewRawSocketConn(iface, bpf, port)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -88,8 +186,20 @@ func NewDHCPServer2(iface string, dhcpServerPort, dhcpRelayPort uint16) (*DHCPSe
|
||||
}, conn, nil
|
||||
}
|
||||
|
||||
type DHCPHandler interface {
|
||||
ServeDHCP(ctx context.Context, pkt Packet, addr *net.UDPAddr, intf *net.Interface) (Packet, []string, error)
|
||||
func NewDHCP6Server2(iface string, port uint16) (*DHCP6Server, *Conn, error) {
|
||||
bpf, err := getRawInstructions(v6bpf)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "getRawInstructions")
|
||||
}
|
||||
conn, err := NewRawSocketConn6(iface, bpf, port)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &DHCP6Server{
|
||||
DHCPServer{
|
||||
conn: conn,
|
||||
},
|
||||
}, conn, nil
|
||||
}
|
||||
|
||||
func (s *DHCPServer) ListenAndServe(handler DHCPHandler) error {
|
||||
@@ -97,14 +207,18 @@ func (s *DHCPServer) ListenAndServe(handler DHCPHandler) error {
|
||||
return s.serveDHCP(handler)
|
||||
}
|
||||
|
||||
func (s *DHCP6Server) ListenAndServe(handler DHCP6Handler) error {
|
||||
defer s.conn.Close()
|
||||
return s.serveDHCP(handler)
|
||||
}
|
||||
|
||||
func (s *DHCPServer) GetConn() *Conn {
|
||||
return s.conn
|
||||
}
|
||||
|
||||
func (s *DHCPServer) serveDHCP(handler DHCPHandler) error {
|
||||
ctx := context.WithValue(context.Background(), "dhcp_server", s)
|
||||
for {
|
||||
pkt, addr, mac, intf, err := s.conn.RecvDHCP()
|
||||
pkt, addr, mac, err := s.conn.RecvDHCP()
|
||||
if err != nil {
|
||||
log.Errorf("Receiving DHCP packet: %s", err)
|
||||
continue
|
||||
@@ -121,7 +235,7 @@ func (s *DHCPServer) serveDHCP(handler DHCPHandler) error {
|
||||
}
|
||||
}()
|
||||
|
||||
resp, targets, err := handler.ServeDHCP(ctx, pkt, addr, intf)
|
||||
resp, targets, err := handler.ServeDHCP(pkt, mac, addr)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP] handler serve error: %v", err)
|
||||
return
|
||||
@@ -136,17 +250,84 @@ func (s *DHCPServer) serveDHCP(handler DHCPHandler) error {
|
||||
log.Debugf("[DHCP] Send packet back to %s", target)
|
||||
targetUdpAddr.IP = net.ParseIP(target)
|
||||
resp.SetGIAddr(targetUdpAddr.IP)
|
||||
if err = s.conn.SendDHCP(resp, &targetUdpAddr, mac, intf); err != nil {
|
||||
if err = s.conn.SendDHCP(resp, &targetUdpAddr, mac); err != nil {
|
||||
log.Errorf("[DHCP] 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, intf); err != nil {
|
||||
if err = s.conn.SendDHCP(resp, addr, mac); err != nil {
|
||||
log.Errorf("[DHCP] failed to response packet for %s: %v", pkt.CHAddr(), err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DHCP6Server) serveDHCP(handler DHCP6Handler) error {
|
||||
for {
|
||||
pkt, addr, mac, err := s.conn.RecvDHCP6()
|
||||
if err != nil {
|
||||
log.Errorf("Receiving DHCP packet: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("[DHCP6] received packet %d from %s mac %s", len(pkt), addr, mac)
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("Serve panic error: %v", r)
|
||||
debug.PrintStack()
|
||||
}
|
||||
}()
|
||||
|
||||
if addr.Port == icmpRAFakePort {
|
||||
// receive a RA solication
|
||||
resp, err := handler.ServeRA(pkt, mac, addr)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP6] handler ServeRA error: %s", err)
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
log.Warningf("[DHCP6] hander ServeRA response null packet")
|
||||
return
|
||||
}
|
||||
|
||||
//log.Debugf("[DHCP] send response packet: %s to interface: %#v", resp.DebugString(), intf)
|
||||
err = s.conn.SendDHCP(resp, addr, mac)
|
||||
if err != nil {
|
||||
log.Errorf("[DHCP] failed to response packet for %s: %v", pkt.CHAddr(), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
resp, targets, err := handler.ServeDHCP(pkt, mac, addr)
|
||||
if err != nil {
|
||||
log.Warningf("[DHCP] handler serve error: %s", err)
|
||||
return
|
||||
}
|
||||
if resp == nil {
|
||||
// log.Warningf("[DHCP] hander response null packet")
|
||||
return
|
||||
}
|
||||
if len(targets) > 0 {
|
||||
targetUdpAddr := *addr
|
||||
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 {
|
||||
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 {
|
||||
log.Errorf("[DHCP6] failed to response packet for %s: %v", pkt.CHAddr(), err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +208,11 @@ type SNetInterface struct {
|
||||
Mask net.IPMask
|
||||
mac string
|
||||
|
||||
Addr6 string
|
||||
Mask6 net.IPMask
|
||||
|
||||
Addr6LinkLocal string
|
||||
|
||||
Mtu int
|
||||
|
||||
VlanId int
|
||||
@@ -231,10 +236,10 @@ func NewNetInterface(name string) *SNetInterface {
|
||||
return n
|
||||
}
|
||||
|
||||
func NewNetInterfaceWithExpectIp(name string, expectIp string) *SNetInterface {
|
||||
func NewNetInterfaceWithExpectIp(name string, expectIp string, expectIp6 string) *SNetInterface {
|
||||
n := new(SNetInterface)
|
||||
n.name = name
|
||||
n.fetchConfig(expectIp)
|
||||
n.FetchConfig2(expectIp, expectIp6)
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -257,10 +262,11 @@ func (n *SNetInterface) FetchInter() *net.Interface {
|
||||
}
|
||||
|
||||
func (n *SNetInterface) FetchConfig() {
|
||||
n.fetchConfig("")
|
||||
n.FetchConfig2("", "")
|
||||
}
|
||||
|
||||
func (n *SNetInterface) fetchConfig(expectIp string) {
|
||||
// FetchConfig2 is used to fetch config with expectIp and expectIp6
|
||||
func (n *SNetInterface) FetchConfig2(expectIp string, expectIp6 string) {
|
||||
n.Addr = ""
|
||||
n.Mask = nil
|
||||
n.mac = ""
|
||||
@@ -278,12 +284,16 @@ func (n *SNetInterface) fetchConfig(expectIp string) {
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||
if ipnet.IP.To4() != nil {
|
||||
n.Addr = ipnet.IP.String()
|
||||
n.Mask = ipnet.Mask
|
||||
if len(expectIp) > 0 && n.Addr != expectIp {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
if (len(expectIp) > 0 && ipnet.IP.String() == expectIp) || (len(expectIp) == 0 && n.Addr == "") {
|
||||
n.Addr = ipnet.IP.String()
|
||||
n.Mask = ipnet.Mask
|
||||
}
|
||||
} else if ipnet.IP.To16() != nil {
|
||||
if ipnet.IP.IsLinkLocalUnicast() {
|
||||
n.Addr6LinkLocal = ipnet.IP.String()
|
||||
} else if (len(expectIp6) > 0 && ipnet.IP.String() == expectIp6) || (len(expectIp6) == 0 && n.Addr6 == "") {
|
||||
n.Addr6 = ipnet.IP.String()
|
||||
n.Mask6 = ipnet.Mask
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,6 +359,10 @@ func (n *SNetInterface) IsSecretInterface() bool {
|
||||
return n.IsSecretAddress(n.Addr, n.Mask)
|
||||
}
|
||||
|
||||
func (n *SNetInterface) IsSecretInterface6() bool {
|
||||
return n.Addr6LinkLocal != "" && n.Addr6 == ""
|
||||
}
|
||||
|
||||
func (n *SNetInterface) IsSecretAddress(addr string, mask []byte) bool {
|
||||
log.Infof("MASK --- %s", mask)
|
||||
if reflect.DeepEqual(mask, SECRET_MASK) && strings.HasPrefix(addr, SECRET_PREFIX) {
|
||||
@@ -364,11 +378,11 @@ func GetSecretInterfaceAddress() (string, int) {
|
||||
return addr, SECRET_MASK_LEN
|
||||
}
|
||||
|
||||
func (n *SNetInterface) GetSlaveAddresses() [][]string {
|
||||
func (n *SNetInterface) GetSlaveAddresses() []SNicAddress {
|
||||
addrs := n.GetAddresses()
|
||||
var slaves = make([][]string, 0)
|
||||
var slaves = make([]SNicAddress, 0)
|
||||
for _, addr := range addrs {
|
||||
if addr[0] != n.Addr {
|
||||
if addr.Addr != n.Addr && addr.Addr != n.Addr6 {
|
||||
slaves = append(slaves, addr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,12 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func (n *SNetInterface) GetAddresses() [][]string {
|
||||
type SNicAddress struct {
|
||||
Addr string
|
||||
MaskLen int
|
||||
}
|
||||
|
||||
func (n *SNetInterface) GetAddresses() []SNicAddress {
|
||||
addrList := iproute2.NewAddress(n.name)
|
||||
addrs4 := n.getAddresses(addrList.List4)
|
||||
addrs6 := n.getAddresses(addrList.List6)
|
||||
@@ -38,19 +43,19 @@ func (n *SNetInterface) GetAddresses() [][]string {
|
||||
return addrs4
|
||||
}
|
||||
|
||||
func (n *SNetInterface) getAddresses(listFunc func() ([]net.IPNet, error)) [][]string {
|
||||
func (n *SNetInterface) getAddresses(listFunc func() ([]net.IPNet, error)) []SNicAddress {
|
||||
ipnets, err := listFunc()
|
||||
if err != nil {
|
||||
log.Errorf("list address %s: %v", n.name, err)
|
||||
return nil
|
||||
}
|
||||
r := make([][]string, len(ipnets))
|
||||
r := make([]SNicAddress, len(ipnets))
|
||||
for i, ipnet := range ipnets {
|
||||
ip := ipnet.IP
|
||||
masklen, _ := ipnet.Mask.Size()
|
||||
r[i] = []string{
|
||||
ip.String(),
|
||||
fmt.Sprintf("%d", masklen),
|
||||
r[i] = SNicAddress{
|
||||
Addr: ip.String(),
|
||||
MaskLen: masklen,
|
||||
}
|
||||
}
|
||||
return r
|
||||
@@ -82,8 +87,24 @@ func (n *SNetInterface) GetRouteSpecs() []iproute2.RouteSpec {
|
||||
return rets
|
||||
}
|
||||
|
||||
func (n *SNetInterface) ClearAddrs() error {
|
||||
cmd := procutils.NewCommand("ip", "addr", "flush", "dev", n.name)
|
||||
func (n *SNetInterface) Shutdown() error {
|
||||
return n.setStatus("down")
|
||||
}
|
||||
|
||||
func (n *SNetInterface) Bringup() error {
|
||||
return n.setStatus("up")
|
||||
}
|
||||
|
||||
func (n *SNetInterface) Reset() error {
|
||||
err := n.Shutdown()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "shutdown")
|
||||
}
|
||||
return n.Bringup()
|
||||
}
|
||||
|
||||
func (n *SNetInterface) setStatus(status string) error {
|
||||
cmd := procutils.NewCommand("ip", "link", "set", n.name, status)
|
||||
msg, err := cmd.Output()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, strings.TrimSpace(string(msg)))
|
||||
|
||||
@@ -17,6 +17,8 @@ package netutils2
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
)
|
||||
|
||||
@@ -82,17 +84,14 @@ func TestNewNetInterface(t *testing.T) {
|
||||
n := NewNetInterface("eth0")
|
||||
t.Logf("NetInterface: %s %s %s %s", n.name, n.Addr, n.Mask.String(), n.mac)
|
||||
addrs := n.GetAddresses()
|
||||
t.Logf("addrs: %s", addrs)
|
||||
t.Logf("addrs: %s", jsonutils.Marshal(addrs).String())
|
||||
slaves := n.GetSlaveAddresses()
|
||||
t.Logf("slaves: %s", slaves)
|
||||
t.Logf("slaves: %s", jsonutils.Marshal(slaves).String())
|
||||
routes := n.GetRouteSpecs()
|
||||
t.Logf("routes: %s", routes)
|
||||
t.Logf("routes: %s", jsonutils.Marshal(routes).String())
|
||||
for i := range routes {
|
||||
t.Logf("route to %s", routes[i].Dst.String())
|
||||
}
|
||||
|
||||
m := NewNetInterface("docker0")
|
||||
m.ClearAddrs()
|
||||
}
|
||||
|
||||
func TestMyDefault(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user