libnetwork ipvs godeps
This commit is contained in:
202
vendor/github.com/docker/libnetwork/LICENSE
generated
vendored
Normal file
202
vendor/github.com/docker/libnetwork/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
33
vendor/github.com/docker/libnetwork/ipvs/BUILD
generated
vendored
Normal file
33
vendor/github.com/docker/libnetwork/ipvs/BUILD
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = select({
|
||||
"@io_bazel_rules_go//go/platform:linux_amd64": [
|
||||
"addr_linux.go",
|
||||
"link_linux.go",
|
||||
"nl_linux.go",
|
||||
"route_linux.go",
|
||||
"tc_linux.go",
|
||||
"xfrm_linux.go",
|
||||
"xfrm_policy_linux.go",
|
||||
"xfrm_state_linux.go",
|
||||
],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
147
vendor/github.com/docker/libnetwork/ipvs/constants.go
generated
vendored
Normal file
147
vendor/github.com/docker/libnetwork/ipvs/constants.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
// +build linux
|
||||
|
||||
package ipvs
|
||||
|
||||
const (
|
||||
genlCtrlID = 0x10
|
||||
)
|
||||
|
||||
// GENL control commands
|
||||
const (
|
||||
genlCtrlCmdUnspec uint8 = iota
|
||||
genlCtrlCmdNewFamily
|
||||
genlCtrlCmdDelFamily
|
||||
genlCtrlCmdGetFamily
|
||||
)
|
||||
|
||||
// GENL family attributes
|
||||
const (
|
||||
genlCtrlAttrUnspec int = iota
|
||||
genlCtrlAttrFamilyID
|
||||
genlCtrlAttrFamilyName
|
||||
)
|
||||
|
||||
// IPVS genl commands
|
||||
const (
|
||||
ipvsCmdUnspec uint8 = iota
|
||||
ipvsCmdNewService
|
||||
ipvsCmdSetService
|
||||
ipvsCmdDelService
|
||||
ipvsCmdGetService
|
||||
ipvsCmdNewDest
|
||||
ipvsCmdSetDest
|
||||
ipvsCmdDelDest
|
||||
ipvsCmdGetDest
|
||||
ipvsCmdNewDaemon
|
||||
ipvsCmdDelDaemon
|
||||
ipvsCmdGetDaemon
|
||||
ipvsCmdSetConfig
|
||||
ipvsCmdGetConfig
|
||||
ipvsCmdSetInfo
|
||||
ipvsCmdGetInfo
|
||||
ipvsCmdZero
|
||||
ipvsCmdFlush
|
||||
)
|
||||
|
||||
// Attributes used in the first level of commands
|
||||
const (
|
||||
ipvsCmdAttrUnspec int = iota
|
||||
ipvsCmdAttrService
|
||||
ipvsCmdAttrDest
|
||||
ipvsCmdAttrDaemon
|
||||
ipvsCmdAttrTimeoutTCP
|
||||
ipvsCmdAttrTimeoutTCPFin
|
||||
ipvsCmdAttrTimeoutUDP
|
||||
)
|
||||
|
||||
// Attributes used to describe a service. Used inside nested attribute
|
||||
// ipvsCmdAttrService
|
||||
const (
|
||||
ipvsSvcAttrUnspec int = iota
|
||||
ipvsSvcAttrAddressFamily
|
||||
ipvsSvcAttrProtocol
|
||||
ipvsSvcAttrAddress
|
||||
ipvsSvcAttrPort
|
||||
ipvsSvcAttrFWMark
|
||||
ipvsSvcAttrSchedName
|
||||
ipvsSvcAttrFlags
|
||||
ipvsSvcAttrTimeout
|
||||
ipvsSvcAttrNetmask
|
||||
ipvsSvcAttrStats
|
||||
ipvsSvcAttrPEName
|
||||
)
|
||||
|
||||
// Attributes used to describe a destination (real server). Used
|
||||
// inside nested attribute ipvsCmdAttrDest.
|
||||
const (
|
||||
ipvsDestAttrUnspec int = iota
|
||||
ipvsDestAttrAddress
|
||||
ipvsDestAttrPort
|
||||
ipvsDestAttrForwardingMethod
|
||||
ipvsDestAttrWeight
|
||||
ipvsDestAttrUpperThreshold
|
||||
ipvsDestAttrLowerThreshold
|
||||
ipvsDestAttrActiveConnections
|
||||
ipvsDestAttrInactiveConnections
|
||||
ipvsDestAttrPersistentConnections
|
||||
ipvsDestAttrStats
|
||||
ipvsDestAttrAddressFamily
|
||||
)
|
||||
|
||||
// IPVS Svc Statistics constancs
|
||||
|
||||
const (
|
||||
ipvsSvcStatsUnspec int = iota
|
||||
ipvsSvcStatsConns
|
||||
ipvsSvcStatsPktsIn
|
||||
ipvsSvcStatsPktsOut
|
||||
ipvsSvcStatsBytesIn
|
||||
ipvsSvcStatsBytesOut
|
||||
ipvsSvcStatsCPS
|
||||
ipvsSvcStatsPPSIn
|
||||
ipvsSvcStatsPPSOut
|
||||
ipvsSvcStatsBPSIn
|
||||
ipvsSvcStatsBPSOut
|
||||
)
|
||||
|
||||
// Destination forwarding methods
|
||||
const (
|
||||
// ConnectionFlagFwdmask indicates the mask in the connection
|
||||
// flags which is used by forwarding method bits.
|
||||
ConnectionFlagFwdMask = 0x0007
|
||||
|
||||
// ConnectionFlagMasq is used for masquerade forwarding method.
|
||||
ConnectionFlagMasq = 0x0000
|
||||
|
||||
// ConnectionFlagLocalNode is used for local node forwarding
|
||||
// method.
|
||||
ConnectionFlagLocalNode = 0x0001
|
||||
|
||||
// ConnectionFlagTunnel is used for tunnel mode forwarding
|
||||
// method.
|
||||
ConnectionFlagTunnel = 0x0002
|
||||
|
||||
// ConnectionFlagDirectRoute is used for direct routing
|
||||
// forwarding method.
|
||||
ConnectionFlagDirectRoute = 0x0003
|
||||
)
|
||||
|
||||
const (
|
||||
// RoundRobin distributes jobs equally amongst the available
|
||||
// real servers.
|
||||
RoundRobin = "rr"
|
||||
|
||||
// LeastConnection assigns more jobs to real servers with
|
||||
// fewer active jobs.
|
||||
LeastConnection = "lc"
|
||||
|
||||
// DestinationHashing assigns jobs to servers through looking
|
||||
// up a statically assigned hash table by their destination IP
|
||||
// addresses.
|
||||
DestinationHashing = "dh"
|
||||
|
||||
// SourceHashing assigns jobs to servers through looking up
|
||||
// a statically assigned hash table by their source IP
|
||||
// addresses.
|
||||
SourceHashing = "sh"
|
||||
)
|
161
vendor/github.com/docker/libnetwork/ipvs/ipvs.go
generated
vendored
Normal file
161
vendor/github.com/docker/libnetwork/ipvs/ipvs.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
// +build linux
|
||||
|
||||
package ipvs
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"fmt"
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
// Service defines an IPVS service in its entirety.
|
||||
type Service struct {
|
||||
// Virtual service address.
|
||||
Address net.IP
|
||||
Protocol uint16
|
||||
Port uint16
|
||||
FWMark uint32 // Firewall mark of the service.
|
||||
|
||||
// Virtual service options.
|
||||
SchedName string
|
||||
Flags uint32
|
||||
Timeout uint32
|
||||
Netmask uint32
|
||||
AddressFamily uint16
|
||||
PEName string
|
||||
Stats SvcStats
|
||||
}
|
||||
|
||||
// SvcStats defines an IPVS service statistics
|
||||
type SvcStats struct {
|
||||
Connections uint32
|
||||
PacketsIn uint32
|
||||
PacketsOut uint32
|
||||
BytesIn uint64
|
||||
BytesOut uint64
|
||||
CPS uint32
|
||||
BPSOut uint32
|
||||
PPSIn uint32
|
||||
PPSOut uint32
|
||||
BPSIn uint32
|
||||
}
|
||||
|
||||
// Destination defines an IPVS destination (real server) in its
|
||||
// entirety.
|
||||
type Destination struct {
|
||||
Address net.IP
|
||||
Port uint16
|
||||
Weight int
|
||||
ConnectionFlags uint32
|
||||
AddressFamily uint16
|
||||
UpperThreshold uint32
|
||||
LowerThreshold uint32
|
||||
}
|
||||
|
||||
// Handle provides a namespace specific ipvs handle to program ipvs
|
||||
// rules.
|
||||
type Handle struct {
|
||||
seq uint32
|
||||
sock *nl.NetlinkSocket
|
||||
}
|
||||
|
||||
// New provides a new ipvs handle in the namespace pointed to by the
|
||||
// passed path. It will return a valid handle or an error in case an
|
||||
// error occurred while creating the handle.
|
||||
func New(path string) (*Handle, error) {
|
||||
setup()
|
||||
|
||||
n := netns.None()
|
||||
if path != "" {
|
||||
var err error
|
||||
n, err = netns.GetFromPath(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
defer n.Close()
|
||||
|
||||
sock, err := nl.GetNetlinkSocketAt(n, netns.None(), syscall.NETLINK_GENERIC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Handle{sock: sock}, nil
|
||||
}
|
||||
|
||||
// Close closes the ipvs handle. The handle is invalid after Close
|
||||
// returns.
|
||||
func (i *Handle) Close() {
|
||||
if i.sock != nil {
|
||||
i.sock.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// NewService creates a new ipvs service in the passed handle.
|
||||
func (i *Handle) NewService(s *Service) error {
|
||||
return i.doCmd(s, nil, ipvsCmdNewService)
|
||||
}
|
||||
|
||||
// IsServicePresent queries for the ipvs service in the passed handle.
|
||||
func (i *Handle) IsServicePresent(s *Service) bool {
|
||||
return nil == i.doCmd(s, nil, ipvsCmdGetService)
|
||||
}
|
||||
|
||||
// UpdateService updates an already existing service in the passed
|
||||
// handle.
|
||||
func (i *Handle) UpdateService(s *Service) error {
|
||||
return i.doCmd(s, nil, ipvsCmdSetService)
|
||||
}
|
||||
|
||||
// DelService deletes an already existing service in the passed
|
||||
// handle.
|
||||
func (i *Handle) DelService(s *Service) error {
|
||||
return i.doCmd(s, nil, ipvsCmdDelService)
|
||||
}
|
||||
|
||||
// NewDestination creates a new real server in the passed ipvs
|
||||
// service which should already be existing in the passed handle.
|
||||
func (i *Handle) NewDestination(s *Service, d *Destination) error {
|
||||
return i.doCmd(s, d, ipvsCmdNewDest)
|
||||
}
|
||||
|
||||
// UpdateDestination updates an already existing real server in the
|
||||
// passed ipvs service in the passed handle.
|
||||
func (i *Handle) UpdateDestination(s *Service, d *Destination) error {
|
||||
return i.doCmd(s, d, ipvsCmdSetDest)
|
||||
}
|
||||
|
||||
// DelDestination deletes an already existing real server in the
|
||||
// passed ipvs service in the passed handle.
|
||||
func (i *Handle) DelDestination(s *Service, d *Destination) error {
|
||||
return i.doCmd(s, d, ipvsCmdDelDest)
|
||||
}
|
||||
|
||||
// GetServices returns an array of services configured on the Node
|
||||
func (i *Handle) GetServices() ([]*Service, error) {
|
||||
return i.doGetServicesCmd(nil)
|
||||
}
|
||||
|
||||
// GetDestinations returns an array of Destinations configured for this Service
|
||||
func (i *Handle) GetDestinations(s *Service) ([]*Destination, error) {
|
||||
return i.doGetDestinationsCmd(s, nil)
|
||||
}
|
||||
|
||||
// GetService gets details of a specific IPVS services, useful in updating statisics etc.,
|
||||
func (i *Handle) GetService(s *Service) (*Service, error) {
|
||||
|
||||
res, err := i.doGetServicesCmd(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We are looking for exactly one service otherwise error out
|
||||
if len(res) != 1 {
|
||||
return nil, fmt.Errorf("Expected only one service obtained=%d", len(res))
|
||||
}
|
||||
|
||||
return res[0], nil
|
||||
}
|
546
vendor/github.com/docker/libnetwork/ipvs/netlink.go
generated
vendored
Normal file
546
vendor/github.com/docker/libnetwork/ipvs/netlink.go
generated
vendored
Normal file
@@ -0,0 +1,546 @@
|
||||
// +build linux
|
||||
|
||||
package ipvs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
// For Quick Reference IPVS related netlink message is described at the end of this file.
|
||||
var (
|
||||
native = nl.NativeEndian()
|
||||
ipvsFamily int
|
||||
ipvsOnce sync.Once
|
||||
)
|
||||
|
||||
type genlMsgHdr struct {
|
||||
cmd uint8
|
||||
version uint8
|
||||
reserved uint16
|
||||
}
|
||||
|
||||
type ipvsFlags struct {
|
||||
flags uint32
|
||||
mask uint32
|
||||
}
|
||||
|
||||
func deserializeGenlMsg(b []byte) (hdr *genlMsgHdr) {
|
||||
return (*genlMsgHdr)(unsafe.Pointer(&b[0:unsafe.Sizeof(*hdr)][0]))
|
||||
}
|
||||
|
||||
func (hdr *genlMsgHdr) Serialize() []byte {
|
||||
return (*(*[unsafe.Sizeof(*hdr)]byte)(unsafe.Pointer(hdr)))[:]
|
||||
}
|
||||
|
||||
func (hdr *genlMsgHdr) Len() int {
|
||||
return int(unsafe.Sizeof(*hdr))
|
||||
}
|
||||
|
||||
func (f *ipvsFlags) Serialize() []byte {
|
||||
return (*(*[unsafe.Sizeof(*f)]byte)(unsafe.Pointer(f)))[:]
|
||||
}
|
||||
|
||||
func (f *ipvsFlags) Len() int {
|
||||
return int(unsafe.Sizeof(*f))
|
||||
}
|
||||
|
||||
func setup() {
|
||||
ipvsOnce.Do(func() {
|
||||
var err error
|
||||
if out, err := exec.Command("modprobe", "-va", "ip_vs").CombinedOutput(); err != nil {
|
||||
logrus.Warnf("Running modprobe ip_vs failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
|
||||
}
|
||||
|
||||
ipvsFamily, err = getIPVSFamily()
|
||||
if err != nil {
|
||||
logrus.Error("Could not get ipvs family information from the kernel. It is possible that ipvs is not enabled in your kernel. Native loadbalancing will not work until this is fixed.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func fillService(s *Service) nl.NetlinkRequestData {
|
||||
cmdAttr := nl.NewRtAttr(ipvsCmdAttrService, nil)
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrAddressFamily, nl.Uint16Attr(s.AddressFamily))
|
||||
if s.FWMark != 0 {
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrFWMark, nl.Uint32Attr(s.FWMark))
|
||||
} else {
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrProtocol, nl.Uint16Attr(s.Protocol))
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrAddress, rawIPData(s.Address))
|
||||
|
||||
// Port needs to be in network byte order.
|
||||
portBuf := new(bytes.Buffer)
|
||||
binary.Write(portBuf, binary.BigEndian, s.Port)
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrPort, portBuf.Bytes())
|
||||
}
|
||||
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrSchedName, nl.ZeroTerminated(s.SchedName))
|
||||
if s.PEName != "" {
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrPEName, nl.ZeroTerminated(s.PEName))
|
||||
}
|
||||
f := &ipvsFlags{
|
||||
flags: s.Flags,
|
||||
mask: 0xFFFFFFFF,
|
||||
}
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrFlags, f.Serialize())
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrTimeout, nl.Uint32Attr(s.Timeout))
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsSvcAttrNetmask, nl.Uint32Attr(s.Netmask))
|
||||
return cmdAttr
|
||||
}
|
||||
|
||||
func fillDestinaton(d *Destination) nl.NetlinkRequestData {
|
||||
cmdAttr := nl.NewRtAttr(ipvsCmdAttrDest, nil)
|
||||
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrAddress, rawIPData(d.Address))
|
||||
// Port needs to be in network byte order.
|
||||
portBuf := new(bytes.Buffer)
|
||||
binary.Write(portBuf, binary.BigEndian, d.Port)
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrPort, portBuf.Bytes())
|
||||
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrForwardingMethod, nl.Uint32Attr(d.ConnectionFlags&ConnectionFlagFwdMask))
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrWeight, nl.Uint32Attr(uint32(d.Weight)))
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrUpperThreshold, nl.Uint32Attr(d.UpperThreshold))
|
||||
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrLowerThreshold, nl.Uint32Attr(d.LowerThreshold))
|
||||
|
||||
return cmdAttr
|
||||
}
|
||||
|
||||
func (i *Handle) doCmdwithResponse(s *Service, d *Destination, cmd uint8) ([][]byte, error) {
|
||||
req := newIPVSRequest(cmd)
|
||||
req.Seq = atomic.AddUint32(&i.seq, 1)
|
||||
|
||||
if s == nil {
|
||||
req.Flags |= syscall.NLM_F_DUMP //Flag to dump all messages
|
||||
req.AddData(nl.NewRtAttr(ipvsCmdAttrService, nil)) //Add a dummy attribute
|
||||
} else {
|
||||
req.AddData(fillService(s))
|
||||
}
|
||||
|
||||
if d == nil {
|
||||
if cmd == ipvsCmdGetDest {
|
||||
req.Flags |= syscall.NLM_F_DUMP
|
||||
}
|
||||
|
||||
} else {
|
||||
req.AddData(fillDestinaton(d))
|
||||
}
|
||||
|
||||
res, err := execute(i.sock, req, 0)
|
||||
if err != nil {
|
||||
return [][]byte{}, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (i *Handle) doCmd(s *Service, d *Destination, cmd uint8) error {
|
||||
_, err := i.doCmdwithResponse(s, d, cmd)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func getIPVSFamily() (int, error) {
|
||||
sock, err := nl.GetNetlinkSocketAt(netns.None(), netns.None(), syscall.NETLINK_GENERIC)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer sock.Close()
|
||||
|
||||
req := newGenlRequest(genlCtrlID, genlCtrlCmdGetFamily)
|
||||
req.AddData(nl.NewRtAttr(genlCtrlAttrFamilyName, nl.ZeroTerminated("IPVS")))
|
||||
|
||||
msgs, err := execute(sock, req, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, m := range msgs {
|
||||
hdr := deserializeGenlMsg(m)
|
||||
attrs, err := nl.ParseRouteAttr(m[hdr.Len():])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
switch int(attr.Attr.Type) {
|
||||
case genlCtrlAttrFamilyID:
|
||||
return int(native.Uint16(attr.Value[0:2])), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("no family id in the netlink response")
|
||||
}
|
||||
|
||||
func rawIPData(ip net.IP) []byte {
|
||||
family := nl.GetIPFamily(ip)
|
||||
if family == nl.FAMILY_V4 {
|
||||
return ip.To4()
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
func newIPVSRequest(cmd uint8) *nl.NetlinkRequest {
|
||||
return newGenlRequest(ipvsFamily, cmd)
|
||||
}
|
||||
|
||||
func newGenlRequest(familyID int, cmd uint8) *nl.NetlinkRequest {
|
||||
req := nl.NewNetlinkRequest(familyID, syscall.NLM_F_ACK)
|
||||
req.AddData(&genlMsgHdr{cmd: cmd, version: 1})
|
||||
return req
|
||||
}
|
||||
|
||||
func execute(s *nl.NetlinkSocket, req *nl.NetlinkRequest, resType uint16) ([][]byte, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
if err := s.Send(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pid, err := s.GetPid()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res [][]byte
|
||||
|
||||
done:
|
||||
for {
|
||||
msgs, err := s.Receive()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Seq != req.Seq {
|
||||
continue
|
||||
}
|
||||
if m.Header.Pid != pid {
|
||||
return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_DONE {
|
||||
break done
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_ERROR {
|
||||
error := int32(native.Uint32(m.Data[0:4]))
|
||||
if error == 0 {
|
||||
break done
|
||||
}
|
||||
return nil, syscall.Errno(-error)
|
||||
}
|
||||
if resType != 0 && m.Header.Type != resType {
|
||||
continue
|
||||
}
|
||||
res = append(res, m.Data)
|
||||
if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
|
||||
break done
|
||||
}
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseIP(ip []byte, family uint16) (net.IP, error) {
|
||||
|
||||
var resIP net.IP
|
||||
|
||||
switch family {
|
||||
case syscall.AF_INET:
|
||||
resIP = (net.IP)(ip[:4])
|
||||
case syscall.AF_INET6:
|
||||
resIP = (net.IP)(ip[:16])
|
||||
default:
|
||||
return nil, fmt.Errorf("parseIP Error ip=%v", ip)
|
||||
|
||||
}
|
||||
return resIP, nil
|
||||
}
|
||||
|
||||
// parseStats
|
||||
func assembleStats(msg []byte) (SvcStats, error) {
|
||||
|
||||
var s SvcStats
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(msg)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
attrType := int(attr.Attr.Type)
|
||||
switch attrType {
|
||||
case ipvsSvcStatsConns:
|
||||
s.Connections = native.Uint32(attr.Value)
|
||||
case ipvsSvcStatsPktsIn:
|
||||
s.PacketsIn = native.Uint32(attr.Value)
|
||||
case ipvsSvcStatsPktsOut:
|
||||
s.PacketsOut = native.Uint32(attr.Value)
|
||||
case ipvsSvcStatsBytesIn:
|
||||
s.BytesIn = native.Uint64(attr.Value)
|
||||
case ipvsSvcStatsBytesOut:
|
||||
s.BytesOut = native.Uint64(attr.Value)
|
||||
case ipvsSvcStatsCPS:
|
||||
s.CPS = native.Uint32(attr.Value)
|
||||
case ipvsSvcStatsPPSIn:
|
||||
s.PPSIn = native.Uint32(attr.Value)
|
||||
case ipvsSvcStatsPPSOut:
|
||||
s.PPSOut = native.Uint32(attr.Value)
|
||||
case ipvsSvcStatsBPSIn:
|
||||
s.BPSIn = native.Uint32(attr.Value)
|
||||
case ipvsSvcStatsBPSOut:
|
||||
s.BPSOut = native.Uint32(attr.Value)
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// assembleService assembles a services back from a hain of netlink attributes
|
||||
func assembleService(attrs []syscall.NetlinkRouteAttr) (*Service, error) {
|
||||
|
||||
var s Service
|
||||
|
||||
for _, attr := range attrs {
|
||||
|
||||
attrType := int(attr.Attr.Type)
|
||||
|
||||
switch attrType {
|
||||
|
||||
case ipvsSvcAttrAddressFamily:
|
||||
s.AddressFamily = native.Uint16(attr.Value)
|
||||
case ipvsSvcAttrProtocol:
|
||||
s.Protocol = native.Uint16(attr.Value)
|
||||
case ipvsSvcAttrAddress:
|
||||
ip, err := parseIP(attr.Value, s.AddressFamily)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Address = ip
|
||||
case ipvsSvcAttrPort:
|
||||
s.Port = binary.BigEndian.Uint16(attr.Value)
|
||||
case ipvsSvcAttrFWMark:
|
||||
s.FWMark = native.Uint32(attr.Value)
|
||||
case ipvsSvcAttrSchedName:
|
||||
s.SchedName = nl.BytesToString(attr.Value)
|
||||
case ipvsSvcAttrFlags:
|
||||
s.Flags = native.Uint32(attr.Value)
|
||||
case ipvsSvcAttrTimeout:
|
||||
s.Timeout = native.Uint32(attr.Value)
|
||||
case ipvsSvcAttrNetmask:
|
||||
s.Netmask = native.Uint32(attr.Value)
|
||||
case ipvsSvcAttrStats:
|
||||
stats, err := assembleStats(attr.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Stats = stats
|
||||
}
|
||||
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
// parseService given a ipvs netlink response this function will respond with a valid service entry, an error otherwise
|
||||
func (i *Handle) parseService(msg []byte) (*Service, error) {
|
||||
|
||||
var s *Service
|
||||
|
||||
//Remove General header for this message and parse the NetLink message
|
||||
hdr := deserializeGenlMsg(msg)
|
||||
NetLinkAttrs, err := nl.ParseRouteAttr(msg[hdr.Len():])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(NetLinkAttrs) == 0 {
|
||||
return nil, fmt.Errorf("error no valid netlink message found while parsing service record")
|
||||
}
|
||||
|
||||
//Now Parse and get IPVS related attributes messages packed in this message.
|
||||
ipvsAttrs, err := nl.ParseRouteAttr(NetLinkAttrs[0].Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//Assemble all the IPVS related attribute messages and create a service record
|
||||
s, err = assembleService(ipvsAttrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// doGetServicesCmd a wrapper which could be used commonly for both GetServices() and GetService(*Service)
|
||||
func (i *Handle) doGetServicesCmd(svc *Service) ([]*Service, error) {
|
||||
var res []*Service
|
||||
|
||||
msgs, err := i.doCmdwithResponse(svc, nil, ipvsCmdGetService)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, msg := range msgs {
|
||||
srv, err := i.parseService(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, srv)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func assembleDestination(attrs []syscall.NetlinkRouteAttr) (*Destination, error) {
|
||||
|
||||
var d Destination
|
||||
|
||||
for _, attr := range attrs {
|
||||
|
||||
attrType := int(attr.Attr.Type)
|
||||
|
||||
switch attrType {
|
||||
case ipvsDestAttrAddress:
|
||||
ip, err := parseIP(attr.Value, syscall.AF_INET)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.Address = ip
|
||||
case ipvsDestAttrPort:
|
||||
d.Port = binary.BigEndian.Uint16(attr.Value)
|
||||
case ipvsDestAttrForwardingMethod:
|
||||
d.ConnectionFlags = native.Uint32(attr.Value)
|
||||
case ipvsDestAttrWeight:
|
||||
d.Weight = int(native.Uint16(attr.Value))
|
||||
case ipvsDestAttrUpperThreshold:
|
||||
d.UpperThreshold = native.Uint32(attr.Value)
|
||||
case ipvsDestAttrLowerThreshold:
|
||||
d.LowerThreshold = native.Uint32(attr.Value)
|
||||
case ipvsDestAttrAddressFamily:
|
||||
d.AddressFamily = native.Uint16(attr.Value)
|
||||
}
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
// parseDestination given a ipvs netlink response this function will respond with a valid destination entry, an error otherwise
|
||||
func (i *Handle) parseDestination(msg []byte) (*Destination, error) {
|
||||
var dst *Destination
|
||||
|
||||
//Remove General header for this message
|
||||
hdr := deserializeGenlMsg(msg)
|
||||
NetLinkAttrs, err := nl.ParseRouteAttr(msg[hdr.Len():])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(NetLinkAttrs) == 0 {
|
||||
return nil, fmt.Errorf("error no valid netlink message found while parsing destination record")
|
||||
}
|
||||
|
||||
//Now Parse and get IPVS related attributes messages packed in this message.
|
||||
ipvsAttrs, err := nl.ParseRouteAttr(NetLinkAttrs[0].Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//Assemble netlink attributes and create a Destination record
|
||||
dst, err = assembleDestination(ipvsAttrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// doGetDestinationsCmd a wrapper function to be used by GetDestinations and GetDestination(d) apis
|
||||
func (i *Handle) doGetDestinationsCmd(s *Service, d *Destination) ([]*Destination, error) {
|
||||
|
||||
var res []*Destination
|
||||
|
||||
msgs, err := i.doCmdwithResponse(s, d, ipvsCmdGetDest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, msg := range msgs {
|
||||
dest, err := i.parseDestination(msg)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res = append(res, dest)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// IPVS related netlink message format explained
|
||||
|
||||
/* EACH NETLINK MSG is of the below format, this is what we will receive from execute() api.
|
||||
If we have multiple netlink objects to process like GetServices() etc., execute() will
|
||||
supply an array of this below object
|
||||
|
||||
NETLINK MSG
|
||||
|-----------------------------------|
|
||||
0 1 2 3
|
||||
|--------|--------|--------|--------| -
|
||||
| CMD ID | VER | RESERVED | |==> General Message Header represented by genlMsgHdr
|
||||
|-----------------------------------| -
|
||||
| ATTR LEN | ATTR TYPE | |
|
||||
|-----------------------------------| |
|
||||
| | |
|
||||
| VALUE | |
|
||||
| []byte Array of IPVS MSG | |==> Attribute Message represented by syscall.NetlinkRouteAttr
|
||||
| PADDED BY 4 BYTES | |
|
||||
| | |
|
||||
|-----------------------------------| -
|
||||
|
||||
|
||||
Once We strip genlMsgHdr from above NETLINK MSG, we should parse the VALUE.
|
||||
VALUE will have an array of netlink attributes (syscall.NetlinkRouteAttr) such that each attribute will
|
||||
represent a "Service" or "Destination" object's field. If we assemble these attributes we can construct
|
||||
Service or Destination.
|
||||
|
||||
IPVS MSG
|
||||
|-----------------------------------|
|
||||
0 1 2 3
|
||||
|--------|--------|--------|--------|
|
||||
| ATTR LEN | ATTR TYPE |
|
||||
|-----------------------------------|
|
||||
| |
|
||||
| |
|
||||
| []byte IPVS ATTRIBUTE BY 4 BYTES |
|
||||
| |
|
||||
| |
|
||||
|-----------------------------------|
|
||||
NEXT ATTRIBUTE
|
||||
|-----------------------------------|
|
||||
| ATTR LEN | ATTR TYPE |
|
||||
|-----------------------------------|
|
||||
| |
|
||||
| |
|
||||
| []byte IPVS ATTRIBUTE BY 4 BYTES |
|
||||
| |
|
||||
| |
|
||||
|-----------------------------------|
|
||||
NEXT ATTRIBUTE
|
||||
|-----------------------------------|
|
||||
| ATTR LEN | ATTR TYPE |
|
||||
|-----------------------------------|
|
||||
| |
|
||||
| |
|
||||
| []byte IPVS ATTRIBUTE BY 4 BYTES |
|
||||
| |
|
||||
| |
|
||||
|-----------------------------------|
|
||||
|
||||
*/
|
Reference in New Issue
Block a user