fix: dhcpv6 support, initial support (#22820)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2025-07-03 14:36:59 +08:00
committed by GitHub
parent 5537fcf7be
commit 36f629e349
30 changed files with 1654 additions and 478 deletions
+1 -1
View File
@@ -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() {
+1
View File
@@ -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{})
+4 -4
View File
@@ -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")
}
+3 -2
View File
@@ -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())
}
+9 -10
View File
@@ -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)
}
+135 -65
View File
@@ -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
}
+3 -3
View File
@@ -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)
}
+10 -19
View File
@@ -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
}
+122
View File
@@ -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
}
+26 -16
View File
@@ -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
}
+6 -1
View File
@@ -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)
}
}
}
+90 -16
View File
@@ -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
+3 -1
View File
@@ -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"`
+10
View File
@@ -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"`
+64 -23
View File
@@ -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","%"
1 Measurement MeasurementNote ResourceType Database Metric MetricNote MetricUnit
239 vasmi Vasmi GPU metrics host telegraf eclk eclk, MHz
240 vasmi Vasmi GPU metrics host telegraf gclk gclk, MHz
241 vasmi Vasmi GPU metrics host telegraf aic_power AIC power
242 worker Worker queue worker system system active_worker_cnt Active Worker Count NULL
243 worker Worker queue worker system system max_worker_count Max Worker Count NULL
244 worker Worker queue worker system system detach_worker_cnt Detach worker Count NULL
245 worker Worker queue worker system system queue_cnt Worker Queue Count NULL
246 http_request worker HTTP Request hit Worker queue http_request system system duration.2xx total_workload http code 2xxx duration Total workload NULL
247 http_request worker HTTP Request hit Worker queue http_request system system duration.4xx active_workload http code 4xxx duration Active workload NULL
248 http_request HTTP Request hit http_request system system duration.5xx duration_ms_any http code 5xxx duration Accumulated request duration in milliseconds NULL ms
249 http_request HTTP Request hit http_request system system hit.2xx dura_ms_delta_any http code 2xxx hit Accumulated request duration in milliseconds in last interval NULL ms
250 http_request HTTP Request hit http_request system system hit.4xx hit_any http code 4xxx hit Accumulated request count NULL
251 http_request HTTP Request hit http_request system system hit.5xx hit_delta_any http code 5xxx hit Accumulated request count in last interval NULL
252 process http_request Service process stats HTTP Request hit process system system cpu_percent delay_ms_any CPU percent Average request delay in miilliseconds NULL ms
253 process http_request Service process stats HTTP Request hit process system system mem_percent qps_any Memory percent Averatge request per second NULL
254 process http_request Service process stats HTTP Request hit process system system mem_size duration_ms_2xx Memory size Accumulated request duration in milliseconds for 2xx http code NULL ms
255 process http_request Service process stats HTTP Request hit process system system goroutine_num dura_ms_delta_2xx Goroutine num Accumulated request duration in milliseconds in last interval for 2xx http code NULL ms
256 db_stats http_request Database Stats HTTP Request hit db_stats system system idle hit_2xx Database Idle Accumulated request count for 2xx http code NULL
257 db_stats http_request Database Stats HTTP Request hit db_stats system system in_use hit_delta_2xx Database InUse Accumulated request count in last interval for 2xx http code NULL
258 db_stats http_request Database Stats HTTP Request hit db_stats system system max_idle_closed delay_ms_2xx Database max idle closed Average request delay in miilliseconds for 2xx http code NULL ms
259 db_stats http_request Database Stats HTTP Request hit db_stats system system max_idle_time_closed percent_hit_2xx Database max idle time closed Request hit weight in percentage for 2xx http code NULL %
260 db_stats http_request Database Stats HTTP Request hit db_stats system system max_lifetime_closed percent_duration_2xx Database max lifetime closed Request duration weight in percentage for 2xx http code NULL %
261 db_stats http_request Database Stats HTTP Request hit db_stats system system max_open_connections qps_2xx Database max open connections Averatge request per second for 2xx http code NULL
262 db_stats http_request Database Stats HTTP Request hit db_stats system system open_connections duration_ms_4xx Database open connections Accumulated request duration in milliseconds for 4xx http code NULL ms
263 db_stats http_request Database Stats HTTP Request hit db_stats system system wait_count dura_ms_delta_4xx Database wait count Accumulated request duration in milliseconds in last interval for 4xx http code NULL ms
264 db_stats http_request Database Stats HTTP Request hit db_stats system system wait_duration hit_4xx Database wait duration Accumulated request count for 4xx http code NULL
265 http_request HTTP Request hit system system hit_delta_4xx Accumulated request count in last interval for 4xx http code NULL
266 http_request HTTP Request hit system system delay_ms_4xx Average request delay in miilliseconds for 4xx http code ms
267 http_request HTTP Request hit system system percent_hit_4xx Request hit weight in percentage for 4xx http code %
268 http_request HTTP Request hit system system percent_duration_4xx Request duration weight in percentage for 4xx http code %
269 http_request HTTP Request hit system system qps_4xx Averatge request per second for 4xx http code NULL
270 http_request HTTP Request hit system system duration_ms_5xx Accumulated request duration in milliseconds for 5xx http code ms
271 http_request HTTP Request hit system system dura_ms_delta_5xx Accumulated request duration in milliseconds in last interval for 5xx http code ms
272 http_request HTTP Request hit system system hit_5xx Accumulated request count for 5xx http code NULL
273 http_request HTTP Request hit system system hit_delta_5xx Accumulated request count in last interval for 5xx http code NULL
274 http_request HTTP Request hit system system delay_ms_5xx Average request delay in miilliseconds for 5xx http code ms
275 http_request HTTP Request hit system system percent_hit_5xx Request hit weight in percentage for 5xx http code %
276 http_request HTTP Request hit system system percent_duration_5xx Request duration weight in percentage for 5xx http code %
277 http_request HTTP Request hit system system qps_5xx Averatge request per second for 5xx http code NULL
278 process Service process stats system system cpu_percent CPU percent NULL
279 process Service process stats system system mem_percent Memory percent NULL
280 process Service process stats system system mem_size Memory size NULL
281 process Service process stats system system goroutine_num Goroutine num NULL
282 db_stats Database Stats system system idle Database Idle NULL
283 db_stats Database Stats system system in_use Database InUse NULL
284 db_stats Database Stats system system max_idle_closed Database max idle closed NULL
285 db_stats Database Stats system system max_idle_time_closed Database max idle time closed NULL
286 db_stats Database Stats system system max_lifetime_closed Database max lifetime closed NULL
287 db_stats Database Stats system system max_open_connections Database max open connections NULL
288 db_stats Database Stats system system open_connections Database open connections NULL
289 db_stats Database Stats system system wait_count Database wait count NULL
290 db_stats Database Stats system system wait_duration Database wait duration NULL
291 status_probe Resource status probe results system system count Resouce count for each status NULL
292 status_probe Resource status probe results system system pending_deleted Pending deleted resource count for each status NULL
293 vm_cpu Guest CPU usage guest telegraf usage_active CPU active state utilization rate %
294 vm_cpu Guest CPU usage guest telegraf cpu_usage_pcore CPU utilization rate per core %
295 vm_cpu Guest CPU usage guest telegraf cpu_usage_idle_pcore CPU idle rate per core %
310 vm_netio Guest network traffic guest telegraf bps_sent Send traffic per second bps
311 vm_netio Guest network traffic guest telegraf pps_recv Received packets per second pps
312 vm_netio Guest network traffic guest telegraf pps_sent Send packets per second pps
313 vm_netio Guest network traffic guest telegraf bytes_sent The total number of bytes sent by the network interface byte
314 vm_netio Guest network traffic guest telegraf bytes_recv The total number of bytes received by the network interface byte
315 vm_netio Guest network traffic guest telegraf packets_sent The total number of packets sent by the network interface count
316 vm_netio Guest network traffic guest telegraf packets_recv The total number of packets received by the network interface count
317 pod_netio Pod network traffic container telegraf bps_recv Received traffic per second bps
318 pod_netio Pod network traffic container telegraf bps_sent Send traffic per second bps
319 pod_netio Pod network traffic container telegraf pps_recv Received packets per second pps
320 pod_netio Pod network traffic container telegraf pps_sent Send packets per second pps
321 pod_netio Pod network traffic container telegraf bytes_sent The total number of bytes sent by the network interface byte
322 pod_netio Pod network traffic container telegraf bytes_recv The total number of bytes received by the network interface byte
323 pod_netio Pod network traffic container telegraf packets_sent The total number of packets sent by the network interface count
324 pod_netio Pod network traffic container telegraf packets_recv The total number of packets received by the network interface count
325 cloudaccount_balance Cloud account balance cloudaccount meter_db balance balance NULL
326 container_cpu Container cpu container telegraf usage_rate Container cpu usage rate %
327 container_mem Container memory container telegraf usage_rate Container memory usage rate %
529 oss_netio Object storage network traffic oss telegraf bps_recv Receive byte byte
530 oss_netio Object storage network traffic oss telegraf bps_sent Send byte byte
531 oss_req Object store request oss telegraf req_count request count count
532 bucket_perf Object storage bucket performance monitor oss telegraf upload_delay_ms Bucket upload delay in milliseconds ms
533 bucket_perf Object storage bucket performance monitor oss telegraf download_delay_ms Bucket download delay in milliseconds ms
534 bucket_perf Object storage bucket performance monitor oss telegraf delete_delay_ms Bucket delete delay in milliseconds ms
535 bucket_perf Object storage bucket performance monitor oss telegraf upload_rate_mbps Bucket upload rate in megabits per second Mbps
536 bucket_perf Object storage bucket performance monitor oss telegraf download_rate_mbps Bucket download rate in megabits per second Mbps
537 ping Ping monitor host telegraf packets_transmitted used SNAT port count count
538 ping Ping monitor host telegraf packets_received SNAT connection count count
539 ping Ping monitor host telegraf percent_packet_loss Packet loss rate in percetile %
+39 -113
View File
@@ -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
}
+148
View File
@@ -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
View File
@@ -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)
}
+190
View File
@@ -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
}
+4
View File
@@ -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")
}
+4
View File
@@ -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:
+4
View File
@@ -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
+29
View File
@@ -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)
}
+303
View File
@@ -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
View File
@@ -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
}
}()
}
}
+27 -13
View File
@@ -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)
}
}
+29 -8
View File
@@ -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)))
+5 -6
View File
@@ -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) {