vendor: re-vendor
This commit is contained in:
201
vendor/github.com/containernetworking/plugins/LICENSE
generated
vendored
Normal file
201
vendor/github.com/containernetworking/plugins/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
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.
|
68
vendor/github.com/containernetworking/plugins/pkg/ip/addr.go
generated
vendored
Normal file
68
vendor/github.com/containernetworking/plugins/pkg/ip/addr.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2017 CNI authors
|
||||
//
|
||||
// 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 ip
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
const SETTLE_INTERVAL = 50 * time.Millisecond
|
||||
|
||||
// SettleAddresses waits for all addresses on a link to leave tentative state.
|
||||
// This is particularly useful for ipv6, where all addresses need to do DAD.
|
||||
// There is no easy way to wait for this as an event, so just loop until the
|
||||
// addresses are no longer tentative.
|
||||
// If any addresses are still tentative after timeout seconds, then error.
|
||||
func SettleAddresses(ifName string, timeout int) error {
|
||||
link, err := netlink.LinkByName(ifName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve link: %v", err)
|
||||
}
|
||||
|
||||
deadline := time.Now().Add(time.Duration(timeout) * time.Second)
|
||||
for {
|
||||
addrs, err := netlink.AddrList(link, netlink.FAMILY_ALL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not list addresses: %v", err)
|
||||
}
|
||||
|
||||
if len(addrs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
ok := true
|
||||
for _, addr := range addrs {
|
||||
if addr.Flags&(syscall.IFA_F_TENTATIVE|syscall.IFA_F_DADFAILED) > 0 {
|
||||
ok = false
|
||||
break // Break out of the `range addrs`, not the `for`
|
||||
}
|
||||
}
|
||||
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
if time.Now().After(deadline) {
|
||||
return fmt.Errorf("link %s still has tentative addresses after %d seconds",
|
||||
ifName,
|
||||
timeout)
|
||||
}
|
||||
|
||||
time.Sleep(SETTLE_INTERVAL)
|
||||
}
|
||||
}
|
61
vendor/github.com/containernetworking/plugins/pkg/ip/cidr.go
generated
vendored
Normal file
61
vendor/github.com/containernetworking/plugins/pkg/ip/cidr.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 ip
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"net"
|
||||
)
|
||||
|
||||
// NextIP returns IP incremented by 1
|
||||
func NextIP(ip net.IP) net.IP {
|
||||
i := ipToInt(ip)
|
||||
return intToIP(i.Add(i, big.NewInt(1)))
|
||||
}
|
||||
|
||||
// PrevIP returns IP decremented by 1
|
||||
func PrevIP(ip net.IP) net.IP {
|
||||
i := ipToInt(ip)
|
||||
return intToIP(i.Sub(i, big.NewInt(1)))
|
||||
}
|
||||
|
||||
// Cmp compares two IPs, returning the usual ordering:
|
||||
// a < b : -1
|
||||
// a == b : 0
|
||||
// a > b : 1
|
||||
func Cmp(a, b net.IP) int {
|
||||
aa := ipToInt(a)
|
||||
bb := ipToInt(b)
|
||||
return aa.Cmp(bb)
|
||||
}
|
||||
|
||||
func ipToInt(ip net.IP) *big.Int {
|
||||
if v := ip.To4(); v != nil {
|
||||
return big.NewInt(0).SetBytes(v)
|
||||
}
|
||||
return big.NewInt(0).SetBytes(ip.To16())
|
||||
}
|
||||
|
||||
func intToIP(i *big.Int) net.IP {
|
||||
return net.IP(i.Bytes())
|
||||
}
|
||||
|
||||
// Network masks off the host portion of the IP
|
||||
func Network(ipn *net.IPNet) *net.IPNet {
|
||||
return &net.IPNet{
|
||||
IP: ipn.IP.Mask(ipn.Mask),
|
||||
Mask: ipn.Mask,
|
||||
}
|
||||
}
|
55
vendor/github.com/containernetworking/plugins/pkg/ip/ipforward.go
generated
vendored
Normal file
55
vendor/github.com/containernetworking/plugins/pkg/ip/ipforward.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 ip
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types/current"
|
||||
)
|
||||
|
||||
func EnableIP4Forward() error {
|
||||
return echo1("/proc/sys/net/ipv4/ip_forward")
|
||||
}
|
||||
|
||||
func EnableIP6Forward() error {
|
||||
return echo1("/proc/sys/net/ipv6/conf/all/forwarding")
|
||||
}
|
||||
|
||||
// EnableForward will enable forwarding for all configured
|
||||
// address families
|
||||
func EnableForward(ips []*current.IPConfig) error {
|
||||
v4 := false
|
||||
v6 := false
|
||||
|
||||
for _, ip := range ips {
|
||||
if ip.Version == "4" && !v4 {
|
||||
if err := EnableIP4Forward(); err != nil {
|
||||
return err
|
||||
}
|
||||
v4 = true
|
||||
} else if ip.Version == "6" && !v6 {
|
||||
if err := EnableIP6Forward(); err != nil {
|
||||
return err
|
||||
}
|
||||
v6 = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func echo1(f string) error {
|
||||
return ioutil.WriteFile(f, []byte("1"), 0644)
|
||||
}
|
92
vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq.go
generated
vendored
Normal file
92
vendor/github.com/containernetworking/plugins/pkg/ip/ipmasq.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 ip
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/coreos/go-iptables/iptables"
|
||||
)
|
||||
|
||||
// SetupIPMasq installs iptables rules to masquerade traffic
|
||||
// coming from ipn and going outside of it
|
||||
func SetupIPMasq(ipn *net.IPNet, chain string, comment string) error {
|
||||
isV6 := ipn.IP.To4() == nil
|
||||
|
||||
var ipt *iptables.IPTables
|
||||
var err error
|
||||
var multicastNet string
|
||||
|
||||
if isV6 {
|
||||
ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv6)
|
||||
multicastNet = "ff00::/8"
|
||||
} else {
|
||||
ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv4)
|
||||
multicastNet = "224.0.0.0/4"
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to locate iptables: %v", err)
|
||||
}
|
||||
|
||||
// Create chain if doesn't exist
|
||||
exists := false
|
||||
chains, err := ipt.ListChains("nat")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list chains: %v", err)
|
||||
}
|
||||
for _, ch := range chains {
|
||||
if ch == chain {
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exists {
|
||||
if err = ipt.NewChain("nat", chain); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Packets to this network should not be touched
|
||||
if err := ipt.AppendUnique("nat", chain, "-d", ipn.String(), "-j", "ACCEPT", "-m", "comment", "--comment", comment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Don't masquerade multicast - pods should be able to talk to other pods
|
||||
// on the local network via multicast.
|
||||
if err := ipt.AppendUnique("nat", chain, "!", "-d", multicastNet, "-j", "MASQUERADE", "-m", "comment", "--comment", comment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ipt.AppendUnique("nat", "POSTROUTING", "-s", ipn.String(), "-j", chain, "-m", "comment", "--comment", comment)
|
||||
}
|
||||
|
||||
// TeardownIPMasq undoes the effects of SetupIPMasq
|
||||
func TeardownIPMasq(ipn *net.IPNet, chain string, comment string) error {
|
||||
ipt, err := iptables.New()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to locate iptables: %v", err)
|
||||
}
|
||||
|
||||
if err = ipt.Delete("nat", "POSTROUTING", "-s", ipn.String(), "-j", chain, "-m", "comment", "--comment", comment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = ipt.ClearChain("nat", chain); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ipt.DeleteChain("nat", chain)
|
||||
}
|
219
vendor/github.com/containernetworking/plugins/pkg/ip/link.go
generated
vendored
Normal file
219
vendor/github.com/containernetworking/plugins/pkg/ip/link.go
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 ip
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
"github.com/containernetworking/plugins/pkg/utils/hwaddr"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLinkNotFound = errors.New("link not found")
|
||||
)
|
||||
|
||||
func makeVethPair(name, peer string, mtu int) (netlink.Link, error) {
|
||||
veth := &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: name,
|
||||
Flags: net.FlagUp,
|
||||
MTU: mtu,
|
||||
},
|
||||
PeerName: peer,
|
||||
}
|
||||
if err := netlink.LinkAdd(veth); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return veth, nil
|
||||
}
|
||||
|
||||
func peerExists(name string) bool {
|
||||
if _, err := netlink.LinkByName(name); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func makeVeth(name string, mtu int) (peerName string, veth netlink.Link, err error) {
|
||||
for i := 0; i < 10; i++ {
|
||||
peerName, err = RandomVethName()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
veth, err = makeVethPair(name, peerName, mtu)
|
||||
switch {
|
||||
case err == nil:
|
||||
return
|
||||
|
||||
case os.IsExist(err):
|
||||
if peerExists(peerName) {
|
||||
continue
|
||||
}
|
||||
err = fmt.Errorf("container veth name provided (%v) already exists", name)
|
||||
return
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("failed to make veth pair: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// should really never be hit
|
||||
err = fmt.Errorf("failed to find a unique veth name")
|
||||
return
|
||||
}
|
||||
|
||||
// RandomVethName returns string "veth" with random prefix (hashed from entropy)
|
||||
func RandomVethName() (string, error) {
|
||||
entropy := make([]byte, 4)
|
||||
_, err := rand.Reader.Read(entropy)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to generate random veth name: %v", err)
|
||||
}
|
||||
|
||||
// NetworkManager (recent versions) will ignore veth devices that start with "veth"
|
||||
return fmt.Sprintf("veth%x", entropy), nil
|
||||
}
|
||||
|
||||
func RenameLink(curName, newName string) error {
|
||||
link, err := netlink.LinkByName(curName)
|
||||
if err == nil {
|
||||
err = netlink.LinkSetName(link, newName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ifaceFromNetlinkLink(l netlink.Link) net.Interface {
|
||||
a := l.Attrs()
|
||||
return net.Interface{
|
||||
Index: a.Index,
|
||||
MTU: a.MTU,
|
||||
Name: a.Name,
|
||||
HardwareAddr: a.HardwareAddr,
|
||||
Flags: a.Flags,
|
||||
}
|
||||
}
|
||||
|
||||
// SetupVeth sets up a pair of virtual ethernet devices.
|
||||
// Call SetupVeth from inside the container netns. It will create both veth
|
||||
// devices and move the host-side veth into the provided hostNS namespace.
|
||||
// On success, SetupVeth returns (hostVeth, containerVeth, nil)
|
||||
func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
|
||||
hostVethName, contVeth, err := makeVeth(contVethName, mtu)
|
||||
if err != nil {
|
||||
return net.Interface{}, net.Interface{}, err
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetUp(contVeth); err != nil {
|
||||
return net.Interface{}, net.Interface{}, fmt.Errorf("failed to set %q up: %v", contVethName, err)
|
||||
}
|
||||
|
||||
hostVeth, err := netlink.LinkByName(hostVethName)
|
||||
if err != nil {
|
||||
return net.Interface{}, net.Interface{}, fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd())); err != nil {
|
||||
return net.Interface{}, net.Interface{}, fmt.Errorf("failed to move veth to host netns: %v", err)
|
||||
}
|
||||
|
||||
err = hostNS.Do(func(_ ns.NetNS) error {
|
||||
hostVeth, err = netlink.LinkByName(hostVethName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup %q in %q: %v", hostVethName, hostNS.Path(), err)
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetUp(hostVeth); err != nil {
|
||||
return fmt.Errorf("failed to set %q up: %v", hostVethName, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return net.Interface{}, net.Interface{}, err
|
||||
}
|
||||
return ifaceFromNetlinkLink(hostVeth), ifaceFromNetlinkLink(contVeth), nil
|
||||
}
|
||||
|
||||
// DelLinkByName removes an interface link.
|
||||
func DelLinkByName(ifName string) error {
|
||||
iface, err := netlink.LinkByName(ifName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
if err = netlink.LinkDel(iface); err != nil {
|
||||
return fmt.Errorf("failed to delete %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DelLinkByNameAddr remove an interface returns its IP address
|
||||
// of the specified family
|
||||
func DelLinkByNameAddr(ifName string, family int) (*net.IPNet, error) {
|
||||
iface, err := netlink.LinkByName(ifName)
|
||||
if err != nil {
|
||||
if err != nil && err.Error() == "Link not found" {
|
||||
return nil, ErrLinkNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("failed to lookup %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
addrs, err := netlink.AddrList(iface, family)
|
||||
if err != nil || len(addrs) == 0 {
|
||||
return nil, fmt.Errorf("failed to get IP addresses for %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
if err = netlink.LinkDel(iface); err != nil {
|
||||
return nil, fmt.Errorf("failed to delete %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
return addrs[0].IPNet, nil
|
||||
}
|
||||
|
||||
func SetHWAddrByIP(ifName string, ip4 net.IP, ip6 net.IP) error {
|
||||
iface, err := netlink.LinkByName(ifName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
switch {
|
||||
case ip4 == nil && ip6 == nil:
|
||||
return fmt.Errorf("neither ip4 or ip6 specified")
|
||||
|
||||
case ip4 != nil:
|
||||
{
|
||||
hwAddr, err := hwaddr.GenerateHardwareAddr4(ip4, hwaddr.PrivateMACPrefix)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate hardware addr: %v", err)
|
||||
}
|
||||
if err = netlink.LinkSetHardwareAddr(iface, hwAddr); err != nil {
|
||||
return fmt.Errorf("failed to add hardware addr to %q: %v", ifName, err)
|
||||
}
|
||||
}
|
||||
case ip6 != nil:
|
||||
// TODO: IPv6
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
27
vendor/github.com/containernetworking/plugins/pkg/ip/route.go
generated
vendored
Normal file
27
vendor/github.com/containernetworking/plugins/pkg/ip/route.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 ip
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// AddDefaultRoute sets the default route on the given gateway.
|
||||
func AddDefaultRoute(gw net.IP, dev netlink.Link) error {
|
||||
_, defNet, _ := net.ParseCIDR("0.0.0.0/0")
|
||||
return AddRoute(defNet, gw, dev)
|
||||
}
|
41
vendor/github.com/containernetworking/plugins/pkg/ip/route_linux.go
generated
vendored
Normal file
41
vendor/github.com/containernetworking/plugins/pkg/ip/route_linux.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2015-2017 CNI authors
|
||||
//
|
||||
// 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 ip
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// AddRoute adds a universally-scoped route to a device.
|
||||
func AddRoute(ipn *net.IPNet, gw net.IP, dev netlink.Link) error {
|
||||
return netlink.RouteAdd(&netlink.Route{
|
||||
LinkIndex: dev.Attrs().Index,
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
Dst: ipn,
|
||||
Gw: gw,
|
||||
})
|
||||
}
|
||||
|
||||
// AddHostRoute adds a host-scoped route to a device.
|
||||
func AddHostRoute(ipn *net.IPNet, gw net.IP, dev netlink.Link) error {
|
||||
return netlink.RouteAdd(&netlink.Route{
|
||||
LinkIndex: dev.Attrs().Index,
|
||||
Scope: netlink.SCOPE_HOST,
|
||||
Dst: ipn,
|
||||
Gw: gw,
|
||||
})
|
||||
}
|
34
vendor/github.com/containernetworking/plugins/pkg/ip/route_unspecified.go
generated
vendored
Normal file
34
vendor/github.com/containernetworking/plugins/pkg/ip/route_unspecified.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2015-2017 CNI authors
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build !linux
|
||||
|
||||
package ip
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// AddRoute adds a universally-scoped route to a device.
|
||||
func AddRoute(ipn *net.IPNet, gw net.IP, dev netlink.Link) error {
|
||||
return types.NotImplementedError
|
||||
}
|
||||
|
||||
// AddHostRoute adds a host-scoped route to a device.
|
||||
func AddHostRoute(ipn *net.IPNet, gw net.IP, dev netlink.Link) error {
|
||||
return types.NotImplementedError
|
||||
}
|
40
vendor/github.com/containernetworking/plugins/pkg/ns/README.md
generated
vendored
Normal file
40
vendor/github.com/containernetworking/plugins/pkg/ns/README.md
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
### Namespaces, Threads, and Go
|
||||
On Linux each OS thread can have a different network namespace. Go's thread scheduling model switches goroutines between OS threads based on OS thread load and whether the goroutine would block other goroutines. This can result in a goroutine switching network namespaces without notice and lead to errors in your code.
|
||||
|
||||
### Namespace Switching
|
||||
Switching namespaces with the `ns.Set()` method is not recommended without additional strategies to prevent unexpected namespace changes when your goroutines switch OS threads.
|
||||
|
||||
Go provides the `runtime.LockOSThread()` function to ensure a specific goroutine executes on its current OS thread and prevents any other goroutine from running in that thread until the locked one exits. Careful usage of `LockOSThread()` and goroutines can provide good control over which network namespace a given goroutine executes in.
|
||||
|
||||
For example, you cannot rely on the `ns.Set()` namespace being the current namespace after the `Set()` call unless you do two things. First, the goroutine calling `Set()` must have previously called `LockOSThread()`. Second, you must ensure `runtime.UnlockOSThread()` is not called somewhere in-between. You also cannot rely on the initial network namespace remaining the current network namespace if any other code in your program switches namespaces, unless you have already called `LockOSThread()` in that goroutine. Note that `LockOSThread()` prevents the Go scheduler from optimally scheduling goroutines for best performance, so `LockOSThread()` should only be used in small, isolated goroutines that release the lock quickly.
|
||||
|
||||
### Do() The Recommended Thing
|
||||
The `ns.Do()` method provides **partial** control over network namespaces for you by implementing these strategies. All code dependent on a particular network namespace (including the root namespace) should be wrapped in the `ns.Do()` method to ensure the correct namespace is selected for the duration of your code. For example:
|
||||
|
||||
```go
|
||||
targetNs, err := ns.NewNS()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = targetNs.Do(func(hostNs ns.NetNS) error {
|
||||
dummy := &netlink.Dummy{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: "dummy0",
|
||||
},
|
||||
}
|
||||
return netlink.LinkAdd(dummy)
|
||||
})
|
||||
```
|
||||
|
||||
Note this requirement to wrap every network call is very onerous - any libraries you call might call out to network services such as DNS, and all such calls need to be protected after you call `ns.Do()`. The CNI plugins all exit very soon after calling `ns.Do()` which helps to minimize the problem.
|
||||
|
||||
Also: If the runtime spawns a new OS thread, it will inherit the network namespace of the parent thread, which may have been temporarily switched, and thus the new OS thread will be permanently "stuck in the wrong namespace".
|
||||
|
||||
In short, **there is no safe way to change network namespaces from within a long-lived, multithreaded Go process**. If your daemon process needs to be namespace aware, consider spawning a separate process (like a CNI plugin) for each namespace.
|
||||
|
||||
### Further Reading
|
||||
- https://github.com/golang/go/wiki/LockOSThread
|
||||
- http://morsmachine.dk/go-scheduler
|
||||
- https://github.com/containernetworking/cni/issues/262
|
||||
- https://golang.org/pkg/runtime/
|
||||
- https://www.weave.works/blog/linux-namespaces-and-go-don-t-mix
|
178
vendor/github.com/containernetworking/plugins/pkg/ns/ns.go
generated
vendored
Normal file
178
vendor/github.com/containernetworking/plugins/pkg/ns/ns.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 ns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type NetNS interface {
|
||||
// Executes the passed closure in this object's network namespace,
|
||||
// attempting to restore the original namespace before returning.
|
||||
// However, since each OS thread can have a different network namespace,
|
||||
// and Go's thread scheduling is highly variable, callers cannot
|
||||
// guarantee any specific namespace is set unless operations that
|
||||
// require that namespace are wrapped with Do(). Also, no code called
|
||||
// from Do() should call runtime.UnlockOSThread(), or the risk
|
||||
// of executing code in an incorrect namespace will be greater. See
|
||||
// https://github.com/golang/go/wiki/LockOSThread for further details.
|
||||
Do(toRun func(NetNS) error) error
|
||||
|
||||
// Sets the current network namespace to this object's network namespace.
|
||||
// Note that since Go's thread scheduling is highly variable, callers
|
||||
// cannot guarantee the requested namespace will be the current namespace
|
||||
// after this function is called; to ensure this wrap operations that
|
||||
// require the namespace with Do() instead.
|
||||
Set() error
|
||||
|
||||
// Returns the filesystem path representing this object's network namespace
|
||||
Path() string
|
||||
|
||||
// Returns a file descriptor representing this object's network namespace
|
||||
Fd() uintptr
|
||||
|
||||
// Cleans up this instance of the network namespace; if this instance
|
||||
// is the last user the namespace will be destroyed
|
||||
Close() error
|
||||
}
|
||||
|
||||
type netNS struct {
|
||||
file *os.File
|
||||
mounted bool
|
||||
closed bool
|
||||
}
|
||||
|
||||
// netNS implements the NetNS interface
|
||||
var _ NetNS = &netNS{}
|
||||
|
||||
const (
|
||||
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/magic.h
|
||||
NSFS_MAGIC = 0x6e736673
|
||||
PROCFS_MAGIC = 0x9fa0
|
||||
)
|
||||
|
||||
type NSPathNotExistErr struct{ msg string }
|
||||
|
||||
func (e NSPathNotExistErr) Error() string { return e.msg }
|
||||
|
||||
type NSPathNotNSErr struct{ msg string }
|
||||
|
||||
func (e NSPathNotNSErr) Error() string { return e.msg }
|
||||
|
||||
func IsNSorErr(nspath string) error {
|
||||
stat := syscall.Statfs_t{}
|
||||
if err := syscall.Statfs(nspath, &stat); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = NSPathNotExistErr{msg: fmt.Sprintf("failed to Statfs %q: %v", nspath, err)}
|
||||
} else {
|
||||
err = fmt.Errorf("failed to Statfs %q: %v", nspath, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
switch stat.Type {
|
||||
case PROCFS_MAGIC, NSFS_MAGIC:
|
||||
return nil
|
||||
default:
|
||||
return NSPathNotNSErr{msg: fmt.Sprintf("unknown FS magic on %q: %x", nspath, stat.Type)}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns an object representing the namespace referred to by @path
|
||||
func GetNS(nspath string) (NetNS, error) {
|
||||
err := IsNSorErr(nspath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fd, err := os.Open(nspath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &netNS{file: fd}, nil
|
||||
}
|
||||
|
||||
func (ns *netNS) Path() string {
|
||||
return ns.file.Name()
|
||||
}
|
||||
|
||||
func (ns *netNS) Fd() uintptr {
|
||||
return ns.file.Fd()
|
||||
}
|
||||
|
||||
func (ns *netNS) errorIfClosed() error {
|
||||
if ns.closed {
|
||||
return fmt.Errorf("%q has already been closed", ns.file.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ns *netNS) Do(toRun func(NetNS) error) error {
|
||||
if err := ns.errorIfClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
containedCall := func(hostNS NetNS) error {
|
||||
threadNS, err := GetCurrentNS()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open current netns: %v", err)
|
||||
}
|
||||
defer threadNS.Close()
|
||||
|
||||
// switch to target namespace
|
||||
if err = ns.Set(); err != nil {
|
||||
return fmt.Errorf("error switching to ns %v: %v", ns.file.Name(), err)
|
||||
}
|
||||
defer threadNS.Set() // switch back
|
||||
|
||||
return toRun(hostNS)
|
||||
}
|
||||
|
||||
// save a handle to current network namespace
|
||||
hostNS, err := GetCurrentNS()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to open current namespace: %v", err)
|
||||
}
|
||||
defer hostNS.Close()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
var innerError error
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
runtime.LockOSThread()
|
||||
innerError = containedCall(hostNS)
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
return innerError
|
||||
}
|
||||
|
||||
// WithNetNSPath executes the passed closure under the given network
|
||||
// namespace, restoring the original namespace afterwards.
|
||||
func WithNetNSPath(nspath string, toRun func(NetNS) error) error {
|
||||
ns, err := GetNS(nspath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer ns.Close()
|
||||
return ns.Do(toRun)
|
||||
}
|
149
vendor/github.com/containernetworking/plugins/pkg/ns/ns_linux.go
generated
vendored
Normal file
149
vendor/github.com/containernetworking/plugins/pkg/ns/ns_linux.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright 2015-2017 CNI authors
|
||||
//
|
||||
// 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 ns
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Returns an object representing the current OS thread's network namespace
|
||||
func GetCurrentNS() (NetNS, error) {
|
||||
return GetNS(getCurrentThreadNetNSPath())
|
||||
}
|
||||
|
||||
func getCurrentThreadNetNSPath() string {
|
||||
// /proc/self/ns/net returns the namespace of the main thread, not
|
||||
// of whatever thread this goroutine is running on. Make sure we
|
||||
// use the thread's net namespace since the thread is switching around
|
||||
return fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid())
|
||||
}
|
||||
|
||||
// Creates a new persistent network namespace and returns an object
|
||||
// representing that namespace, without switching to it
|
||||
func NewNS() (NetNS, error) {
|
||||
const nsRunDir = "/var/run/netns"
|
||||
|
||||
b := make([]byte, 16)
|
||||
_, err := rand.Reader.Read(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate random netns name: %v", err)
|
||||
}
|
||||
|
||||
err = os.MkdirAll(nsRunDir, 0755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create an empty file at the mount point
|
||||
nsName := fmt.Sprintf("cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
nsPath := path.Join(nsRunDir, nsName)
|
||||
mountPointFd, err := os.Create(nsPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mountPointFd.Close()
|
||||
|
||||
// Ensure the mount point is cleaned up on errors; if the namespace
|
||||
// was successfully mounted this will have no effect because the file
|
||||
// is in-use
|
||||
defer os.RemoveAll(nsPath)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
// do namespace work in a dedicated goroutine, so that we can safely
|
||||
// Lock/Unlock OSThread without upsetting the lock/unlock state of
|
||||
// the caller of this function
|
||||
var fd *os.File
|
||||
go (func() {
|
||||
defer wg.Done()
|
||||
runtime.LockOSThread()
|
||||
|
||||
var origNS NetNS
|
||||
origNS, err = GetNS(getCurrentThreadNetNSPath())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer origNS.Close()
|
||||
|
||||
// create a new netns on the current thread
|
||||
err = unix.Unshare(unix.CLONE_NEWNET)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer origNS.Set()
|
||||
|
||||
// bind mount the new netns from the current thread onto the mount point
|
||||
err = unix.Mount(getCurrentThreadNetNSPath(), nsPath, "none", unix.MS_BIND, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fd, err = os.Open(nsPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
})()
|
||||
wg.Wait()
|
||||
|
||||
if err != nil {
|
||||
unix.Unmount(nsPath, unix.MNT_DETACH)
|
||||
return nil, fmt.Errorf("failed to create namespace: %v", err)
|
||||
}
|
||||
|
||||
return &netNS{file: fd, mounted: true}, nil
|
||||
}
|
||||
|
||||
func (ns *netNS) Close() error {
|
||||
if err := ns.errorIfClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ns.file.Close(); err != nil {
|
||||
return fmt.Errorf("Failed to close %q: %v", ns.file.Name(), err)
|
||||
}
|
||||
ns.closed = true
|
||||
|
||||
if ns.mounted {
|
||||
if err := unix.Unmount(ns.file.Name(), unix.MNT_DETACH); err != nil {
|
||||
return fmt.Errorf("Failed to unmount namespace %s: %v", ns.file.Name(), err)
|
||||
}
|
||||
if err := os.RemoveAll(ns.file.Name()); err != nil {
|
||||
return fmt.Errorf("Failed to clean up namespace %s: %v", ns.file.Name(), err)
|
||||
}
|
||||
ns.mounted = false
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ns *netNS) Set() error {
|
||||
if err := ns.errorIfClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := unix.Setns(int(ns.Fd()), unix.CLONE_NEWNET); err != nil {
|
||||
return fmt.Errorf("Error switching to ns %v: %v", ns.file.Name(), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
36
vendor/github.com/containernetworking/plugins/pkg/ns/ns_unspecified.go
generated
vendored
Normal file
36
vendor/github.com/containernetworking/plugins/pkg/ns/ns_unspecified.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright 2015-2017 CNI authors
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build !linux
|
||||
|
||||
package ns
|
||||
|
||||
import "github.com/containernetworking/cni/pkg/types"
|
||||
|
||||
// Returns an object representing the current OS thread's network namespace
|
||||
func GetCurrentNS() (NetNS, error) {
|
||||
return nil, types.NotImplementedError
|
||||
}
|
||||
|
||||
func NewNS() (NetNS, error) {
|
||||
return nil, types.NotImplementedError
|
||||
}
|
||||
|
||||
func (ns *netNS) Close() error {
|
||||
return types.NotImplementedError
|
||||
}
|
||||
|
||||
func (ns *netNS) Set() error {
|
||||
return types.NotImplementedError
|
||||
}
|
63
vendor/github.com/containernetworking/plugins/pkg/utils/hwaddr/hwaddr.go
generated
vendored
Normal file
63
vendor/github.com/containernetworking/plugins/pkg/utils/hwaddr/hwaddr.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2016 CNI authors
|
||||
//
|
||||
// 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 hwaddr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
const (
|
||||
ipRelevantByteLen = 4
|
||||
PrivateMACPrefixString = "0a:58"
|
||||
)
|
||||
|
||||
var (
|
||||
// private mac prefix safe to use
|
||||
PrivateMACPrefix = []byte{0x0a, 0x58}
|
||||
)
|
||||
|
||||
type SupportIp4OnlyErr struct{ msg string }
|
||||
|
||||
func (e SupportIp4OnlyErr) Error() string { return e.msg }
|
||||
|
||||
type MacParseErr struct{ msg string }
|
||||
|
||||
func (e MacParseErr) Error() string { return e.msg }
|
||||
|
||||
type InvalidPrefixLengthErr struct{ msg string }
|
||||
|
||||
func (e InvalidPrefixLengthErr) Error() string { return e.msg }
|
||||
|
||||
// GenerateHardwareAddr4 generates 48 bit virtual mac addresses based on the IP4 input.
|
||||
func GenerateHardwareAddr4(ip net.IP, prefix []byte) (net.HardwareAddr, error) {
|
||||
switch {
|
||||
|
||||
case ip.To4() == nil:
|
||||
return nil, SupportIp4OnlyErr{msg: "GenerateHardwareAddr4 only supports valid IPv4 address as input"}
|
||||
|
||||
case len(prefix) != len(PrivateMACPrefix):
|
||||
return nil, InvalidPrefixLengthErr{msg: fmt.Sprintf(
|
||||
"Prefix has length %d instead of %d", len(prefix), len(PrivateMACPrefix)),
|
||||
}
|
||||
}
|
||||
|
||||
ipByteLen := len(ip)
|
||||
return (net.HardwareAddr)(
|
||||
append(
|
||||
prefix,
|
||||
ip[ipByteLen-ipRelevantByteLen:ipByteLen]...),
|
||||
), nil
|
||||
}
|
217
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/allocator.go
generated
vendored
Normal file
217
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/allocator.go
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 allocator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types/current"
|
||||
"github.com/containernetworking/plugins/pkg/ip"
|
||||
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend"
|
||||
)
|
||||
|
||||
type IPAllocator struct {
|
||||
rangeset *RangeSet
|
||||
store backend.Store
|
||||
rangeID string // Used for tracking last reserved ip
|
||||
}
|
||||
|
||||
func NewIPAllocator(s *RangeSet, store backend.Store, id int) *IPAllocator {
|
||||
return &IPAllocator{
|
||||
rangeset: s,
|
||||
store: store,
|
||||
rangeID: strconv.Itoa(id),
|
||||
}
|
||||
}
|
||||
|
||||
// Get alocates an IP
|
||||
func (a *IPAllocator) Get(id string, requestedIP net.IP) (*current.IPConfig, error) {
|
||||
a.store.Lock()
|
||||
defer a.store.Unlock()
|
||||
|
||||
var reservedIP *net.IPNet
|
||||
var gw net.IP
|
||||
|
||||
if requestedIP != nil {
|
||||
if err := canonicalizeIP(&requestedIP); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := a.rangeset.RangeFor(requestedIP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if requestedIP.Equal(r.Gateway) {
|
||||
return nil, fmt.Errorf("requested ip %s is subnet's gateway", requestedIP.String())
|
||||
}
|
||||
|
||||
reserved, err := a.store.Reserve(id, requestedIP, a.rangeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !reserved {
|
||||
return nil, fmt.Errorf("requested IP address %s is not available in range set %s", requestedIP, a.rangeset.String())
|
||||
}
|
||||
reservedIP = &net.IPNet{IP: requestedIP, Mask: r.Subnet.Mask}
|
||||
gw = r.Gateway
|
||||
|
||||
} else {
|
||||
iter, err := a.GetIter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
reservedIP, gw = iter.Next()
|
||||
if reservedIP == nil {
|
||||
break
|
||||
}
|
||||
|
||||
reserved, err := a.store.Reserve(id, reservedIP.IP, a.rangeID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reserved {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if reservedIP == nil {
|
||||
return nil, fmt.Errorf("no IP addresses available in range set: %s", a.rangeset.String())
|
||||
}
|
||||
version := "4"
|
||||
if reservedIP.IP.To4() == nil {
|
||||
version = "6"
|
||||
}
|
||||
|
||||
return ¤t.IPConfig{
|
||||
Version: version,
|
||||
Address: *reservedIP,
|
||||
Gateway: gw,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Release clears all IPs allocated for the container with given ID
|
||||
func (a *IPAllocator) Release(id string) error {
|
||||
a.store.Lock()
|
||||
defer a.store.Unlock()
|
||||
|
||||
return a.store.ReleaseByID(id)
|
||||
}
|
||||
|
||||
type RangeIter struct {
|
||||
rangeset *RangeSet
|
||||
|
||||
// The current range id
|
||||
rangeIdx int
|
||||
|
||||
// Our current position
|
||||
cur net.IP
|
||||
|
||||
// The IP and range index where we started iterating; if we hit this again, we're done.
|
||||
startIP net.IP
|
||||
startRange int
|
||||
}
|
||||
|
||||
// GetIter encapsulates the strategy for this allocator.
|
||||
// We use a round-robin strategy, attempting to evenly use the whole set.
|
||||
// More specifically, a crash-looping container will not see the same IP until
|
||||
// the entire range has been run through.
|
||||
// We may wish to consider avoiding recently-released IPs in the future.
|
||||
func (a *IPAllocator) GetIter() (*RangeIter, error) {
|
||||
iter := RangeIter{
|
||||
rangeset: a.rangeset,
|
||||
}
|
||||
|
||||
// Round-robin by trying to allocate from the last reserved IP + 1
|
||||
startFromLastReservedIP := false
|
||||
|
||||
// We might get a last reserved IP that is wrong if the range indexes changed.
|
||||
// This is not critical, we just lose round-robin this one time.
|
||||
lastReservedIP, err := a.store.LastReservedIP(a.rangeID)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
log.Printf("Error retrieving last reserved ip: %v", err)
|
||||
} else if lastReservedIP != nil {
|
||||
startFromLastReservedIP = a.rangeset.Contains(lastReservedIP)
|
||||
}
|
||||
|
||||
// Find the range in the set with this IP
|
||||
if startFromLastReservedIP {
|
||||
for i, r := range *a.rangeset {
|
||||
if r.Contains(lastReservedIP) {
|
||||
iter.rangeIdx = i
|
||||
iter.startRange = i
|
||||
|
||||
// We advance the cursor on every Next(), so the first call
|
||||
// to next() will return lastReservedIP + 1
|
||||
iter.cur = lastReservedIP
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iter.rangeIdx = 0
|
||||
iter.startRange = 0
|
||||
iter.startIP = (*a.rangeset)[0].RangeStart
|
||||
}
|
||||
return &iter, nil
|
||||
}
|
||||
|
||||
// Next returns the next IP, its mask, and its gateway. Returns nil
|
||||
// if the iterator has been exhausted
|
||||
func (i *RangeIter) Next() (*net.IPNet, net.IP) {
|
||||
r := (*i.rangeset)[i.rangeIdx]
|
||||
|
||||
// If this is the first time iterating and we're not starting in the middle
|
||||
// of the range, then start at rangeStart, which is inclusive
|
||||
if i.cur == nil {
|
||||
i.cur = r.RangeStart
|
||||
i.startIP = i.cur
|
||||
if i.cur.Equal(r.Gateway) {
|
||||
return i.Next()
|
||||
}
|
||||
return &net.IPNet{IP: i.cur, Mask: r.Subnet.Mask}, r.Gateway
|
||||
}
|
||||
|
||||
// If we've reached the end of this range, we need to advance the range
|
||||
// RangeEnd is inclusive as well
|
||||
if i.cur.Equal(r.RangeEnd) {
|
||||
i.rangeIdx += 1
|
||||
i.rangeIdx %= len(*i.rangeset)
|
||||
r = (*i.rangeset)[i.rangeIdx]
|
||||
|
||||
i.cur = r.RangeStart
|
||||
} else {
|
||||
i.cur = ip.NextIP(i.cur)
|
||||
}
|
||||
|
||||
if i.startIP == nil {
|
||||
i.startIP = i.cur
|
||||
} else if i.rangeIdx == i.startRange && i.cur.Equal(i.startIP) {
|
||||
// IF we've looped back to where we started, give up
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if i.cur.Equal(r.Gateway) {
|
||||
return i.Next()
|
||||
}
|
||||
|
||||
return &net.IPNet{IP: i.cur, Mask: r.Subnet.Mask}, r.Gateway
|
||||
}
|
151
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/config.go
generated
vendored
Normal file
151
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/config.go
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 allocator
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
types020 "github.com/containernetworking/cni/pkg/types/020"
|
||||
)
|
||||
|
||||
// The top-level network config, just so we can get the IPAM block
|
||||
type Net struct {
|
||||
Name string `json:"name"`
|
||||
CNIVersion string `json:"cniVersion"`
|
||||
IPAM *IPAMConfig `json:"ipam"`
|
||||
Args *struct {
|
||||
A *IPAMArgs `json:"cni"`
|
||||
} `json:"args"`
|
||||
}
|
||||
|
||||
// IPAMConfig represents the IP related network configuration.
|
||||
// This nests Range because we initially only supported a single
|
||||
// range directly, and wish to preserve backwards compatability
|
||||
type IPAMConfig struct {
|
||||
*Range
|
||||
Name string
|
||||
Type string `json:"type"`
|
||||
Routes []*types.Route `json:"routes"`
|
||||
DataDir string `json:"dataDir"`
|
||||
ResolvConf string `json:"resolvConf"`
|
||||
Ranges []RangeSet `json:"ranges"`
|
||||
IPArgs []net.IP `json:"-"` // Requested IPs from CNI_ARGS and args
|
||||
}
|
||||
|
||||
type IPAMEnvArgs struct {
|
||||
types.CommonArgs
|
||||
IP net.IP `json:"ip,omitempty"`
|
||||
}
|
||||
|
||||
type IPAMArgs struct {
|
||||
IPs []net.IP `json:"ips"`
|
||||
}
|
||||
|
||||
type RangeSet []Range
|
||||
|
||||
type Range struct {
|
||||
RangeStart net.IP `json:"rangeStart,omitempty"` // The first ip, inclusive
|
||||
RangeEnd net.IP `json:"rangeEnd,omitempty"` // The last ip, inclusive
|
||||
Subnet types.IPNet `json:"subnet"`
|
||||
Gateway net.IP `json:"gateway,omitempty"`
|
||||
}
|
||||
|
||||
// NewIPAMConfig creates a NetworkConfig from the given network name.
|
||||
func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
|
||||
n := Net{}
|
||||
if err := json.Unmarshal(bytes, &n); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if n.IPAM == nil {
|
||||
return nil, "", fmt.Errorf("IPAM config missing 'ipam' key")
|
||||
}
|
||||
|
||||
// Parse custom IP from both env args *and* the top-level args config
|
||||
if envArgs != "" {
|
||||
e := IPAMEnvArgs{}
|
||||
err := types.LoadArgs(envArgs, &e)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if e.IP != nil {
|
||||
n.IPAM.IPArgs = []net.IP{e.IP}
|
||||
}
|
||||
}
|
||||
|
||||
if n.Args != nil && n.Args.A != nil && len(n.Args.A.IPs) != 0 {
|
||||
n.IPAM.IPArgs = append(n.IPAM.IPArgs, n.Args.A.IPs...)
|
||||
}
|
||||
|
||||
for idx, _ := range n.IPAM.IPArgs {
|
||||
if err := canonicalizeIP(&n.IPAM.IPArgs[idx]); err != nil {
|
||||
return nil, "", fmt.Errorf("cannot understand ip: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If a single range (old-style config) is specified, prepend it to
|
||||
// the Ranges array
|
||||
if n.IPAM.Range != nil && n.IPAM.Range.Subnet.IP != nil {
|
||||
n.IPAM.Ranges = append([]RangeSet{{*n.IPAM.Range}}, n.IPAM.Ranges...)
|
||||
}
|
||||
n.IPAM.Range = nil
|
||||
|
||||
if len(n.IPAM.Ranges) == 0 {
|
||||
return nil, "", fmt.Errorf("no IP ranges specified")
|
||||
}
|
||||
|
||||
// Validate all ranges
|
||||
numV4 := 0
|
||||
numV6 := 0
|
||||
for i, _ := range n.IPAM.Ranges {
|
||||
if err := n.IPAM.Ranges[i].Canonicalize(); err != nil {
|
||||
return nil, "", fmt.Errorf("invalid range set %d: %s", i, err)
|
||||
}
|
||||
|
||||
if n.IPAM.Ranges[i][0].RangeStart.To4() != nil {
|
||||
numV4++
|
||||
} else {
|
||||
numV6++
|
||||
}
|
||||
}
|
||||
|
||||
// CNI spec 0.2.0 and below supported only one v4 and v6 address
|
||||
if numV4 > 1 || numV6 > 1 {
|
||||
for _, v := range types020.SupportedVersions {
|
||||
if n.CNIVersion == v {
|
||||
return nil, "", fmt.Errorf("CNI version %v does not support more than 1 address per family", n.CNIVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for overlaps
|
||||
l := len(n.IPAM.Ranges)
|
||||
for i, p1 := range n.IPAM.Ranges[:l-1] {
|
||||
for j, p2 := range n.IPAM.Ranges[i+1:] {
|
||||
if p1.Overlaps(&p2) {
|
||||
return nil, "", fmt.Errorf("range set %d overlaps with %d", i, (i + j + 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy net name into IPAM so not to drag Net struct around
|
||||
n.IPAM.Name = n.Name
|
||||
|
||||
return n.IPAM, n.CNIVersion, nil
|
||||
}
|
164
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/range.go
generated
vendored
Normal file
164
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/range.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2017 CNI authors
|
||||
//
|
||||
// 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 allocator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/containernetworking/plugins/pkg/ip"
|
||||
)
|
||||
|
||||
// Canonicalize takes a given range and ensures that all information is consistent,
|
||||
// filling out Start, End, and Gateway with sane values if missing
|
||||
func (r *Range) Canonicalize() error {
|
||||
if err := canonicalizeIP(&r.Subnet.IP); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Can't create an allocator for a network with no addresses, eg
|
||||
// a /32 or /31
|
||||
ones, masklen := r.Subnet.Mask.Size()
|
||||
if ones > masklen-2 {
|
||||
return fmt.Errorf("Network %s too small to allocate from", (*net.IPNet)(&r.Subnet).String())
|
||||
}
|
||||
|
||||
if len(r.Subnet.IP) != len(r.Subnet.Mask) {
|
||||
return fmt.Errorf("IPNet IP and Mask version mismatch")
|
||||
}
|
||||
|
||||
// If the gateway is nil, claim .1
|
||||
if r.Gateway == nil {
|
||||
r.Gateway = ip.NextIP(r.Subnet.IP)
|
||||
} else {
|
||||
if err := canonicalizeIP(&r.Gateway); err != nil {
|
||||
return err
|
||||
}
|
||||
subnet := (net.IPNet)(r.Subnet)
|
||||
if !subnet.Contains(r.Gateway) {
|
||||
return fmt.Errorf("gateway %s not in network %s", r.Gateway.String(), subnet.String())
|
||||
}
|
||||
}
|
||||
|
||||
// RangeStart: If specified, make sure it's sane (inside the subnet),
|
||||
// otherwise use the first free IP (i.e. .1) - this will conflict with the
|
||||
// gateway but we skip it in the iterator
|
||||
if r.RangeStart != nil {
|
||||
if err := canonicalizeIP(&r.RangeStart); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !r.Contains(r.RangeStart) {
|
||||
return fmt.Errorf("RangeStart %s not in network %s", r.RangeStart.String(), (*net.IPNet)(&r.Subnet).String())
|
||||
}
|
||||
} else {
|
||||
r.RangeStart = ip.NextIP(r.Subnet.IP)
|
||||
}
|
||||
|
||||
// RangeEnd: If specified, verify sanity. Otherwise, add a sensible default
|
||||
// (e.g. for a /24: .254 if IPv4, ::255 if IPv6)
|
||||
if r.RangeEnd != nil {
|
||||
if err := canonicalizeIP(&r.RangeEnd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !r.Contains(r.RangeEnd) {
|
||||
return fmt.Errorf("RangeEnd %s not in network %s", r.RangeEnd.String(), (*net.IPNet)(&r.Subnet).String())
|
||||
}
|
||||
} else {
|
||||
r.RangeEnd = lastIP(r.Subnet)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidIP checks if a given ip is a valid, allocatable address in a given Range
|
||||
func (r *Range) Contains(addr net.IP) bool {
|
||||
if err := canonicalizeIP(&addr); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
subnet := (net.IPNet)(r.Subnet)
|
||||
|
||||
// Not the same address family
|
||||
if len(addr) != len(r.Subnet.IP) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Not in network
|
||||
if !subnet.Contains(addr) {
|
||||
return false
|
||||
}
|
||||
|
||||
// We ignore nils here so we can use this function as we initialize the range.
|
||||
if r.RangeStart != nil {
|
||||
// Before the range start
|
||||
if ip.Cmp(addr, r.RangeStart) < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if r.RangeEnd != nil {
|
||||
if ip.Cmp(addr, r.RangeEnd) > 0 {
|
||||
// After the range end
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Overlaps returns true if there is any overlap between ranges
|
||||
func (r *Range) Overlaps(r1 *Range) bool {
|
||||
// different familes
|
||||
if len(r.RangeStart) != len(r1.RangeStart) {
|
||||
return false
|
||||
}
|
||||
|
||||
return r.Contains(r1.RangeStart) ||
|
||||
r.Contains(r1.RangeEnd) ||
|
||||
r1.Contains(r.RangeStart) ||
|
||||
r1.Contains(r.RangeEnd)
|
||||
}
|
||||
|
||||
func (r *Range) String() string {
|
||||
return fmt.Sprintf("%s-%s", r.RangeStart.String(), r.RangeEnd.String())
|
||||
}
|
||||
|
||||
// canonicalizeIP makes sure a provided ip is in standard form
|
||||
func canonicalizeIP(ip *net.IP) error {
|
||||
if ip.To4() != nil {
|
||||
*ip = ip.To4()
|
||||
return nil
|
||||
} else if ip.To16() != nil {
|
||||
*ip = ip.To16()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("IP %s not v4 nor v6", *ip)
|
||||
}
|
||||
|
||||
// Determine the last IP of a subnet, excluding the broadcast if IPv4
|
||||
func lastIP(subnet types.IPNet) net.IP {
|
||||
var end net.IP
|
||||
for i := 0; i < len(subnet.IP); i++ {
|
||||
end = append(end, subnet.IP[i]|^subnet.Mask[i])
|
||||
}
|
||||
if subnet.IP.To4() != nil {
|
||||
end[3]--
|
||||
}
|
||||
|
||||
return end
|
||||
}
|
97
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/range_set.go
generated
vendored
Normal file
97
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator/range_set.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright 2017 CNI authors
|
||||
//
|
||||
// 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 allocator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Contains returns true if any range in this set contains an IP
|
||||
func (s *RangeSet) Contains(addr net.IP) bool {
|
||||
r, _ := s.RangeFor(addr)
|
||||
return r != nil
|
||||
}
|
||||
|
||||
// RangeFor finds the range that contains an IP, or nil if not found
|
||||
func (s *RangeSet) RangeFor(addr net.IP) (*Range, error) {
|
||||
if err := canonicalizeIP(&addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, r := range *s {
|
||||
if r.Contains(addr) {
|
||||
return &r, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%s not in range set %s", addr.String(), s.String())
|
||||
}
|
||||
|
||||
// Overlaps returns true if any ranges in any set overlap with this one
|
||||
func (s *RangeSet) Overlaps(p1 *RangeSet) bool {
|
||||
for _, r := range *s {
|
||||
for _, r1 := range *p1 {
|
||||
if r.Overlaps(&r1) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Canonicalize ensures the RangeSet is in a standard form, and detects any
|
||||
// invalid input. Call Range.Canonicalize() on every Range in the set
|
||||
func (s *RangeSet) Canonicalize() error {
|
||||
if len(*s) == 0 {
|
||||
return fmt.Errorf("empty range set")
|
||||
}
|
||||
|
||||
fam := 0
|
||||
for i, _ := range *s {
|
||||
if err := (*s)[i].Canonicalize(); err != nil {
|
||||
return err
|
||||
}
|
||||
if i == 0 {
|
||||
fam = len((*s)[i].RangeStart)
|
||||
} else {
|
||||
if fam != len((*s)[i].RangeStart) {
|
||||
return fmt.Errorf("mixed address families")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure none of the ranges in the set overlap
|
||||
l := len(*s)
|
||||
for i, r1 := range (*s)[:l-1] {
|
||||
for _, r2 := range (*s)[i+1:] {
|
||||
if r1.Overlaps(&r2) {
|
||||
return fmt.Errorf("subnets %s and %s overlap", r1.String(), r2.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RangeSet) String() string {
|
||||
out := []string{}
|
||||
for _, r := range *s {
|
||||
out = append(out, r.String())
|
||||
}
|
||||
|
||||
return strings.Join(out, ",")
|
||||
}
|
27
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/store.go
generated
vendored
Normal file
27
vendor/github.com/containernetworking/plugins/plugins/ipam/host-local/backend/store.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2015 CNI authors
|
||||
//
|
||||
// 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 backend
|
||||
|
||||
import "net"
|
||||
|
||||
type Store interface {
|
||||
Lock() error
|
||||
Unlock() error
|
||||
Close() error
|
||||
Reserve(id string, ip net.IP, rangeID string) (bool, error)
|
||||
LastReservedIP(rangeID string) (net.IP, error)
|
||||
Release(ip net.IP) error
|
||||
ReleaseByID(id string) error
|
||||
}
|
Reference in New Issue
Block a user