mirror of
https://github.com/clearlinux/rkt.git
synced 2026-09-06 22:01:54 +00:00
stage1: add ipvlan network plugin
This plugin is very similar to macvlan but let's the secondary interfaces use the primary interface's MAC address instead of generating their own one. This commit also updates the revisions for all Godeps from the appc/cni repository.
This commit is contained in:
Generated
+12
-8
@@ -21,35 +21,39 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/pkg/ip",
|
||||
"Rev": "88377fa3466eea30817b038c69ac06686e7655b7"
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/pkg/ns",
|
||||
"Rev": "88377fa3466eea30817b038c69ac06686e7655b7"
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/pkg/plugin",
|
||||
"Rev": "88377fa3466eea30817b038c69ac06686e7655b7"
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/pkg/skel",
|
||||
"Rev": "88377fa3466eea30817b038c69ac06686e7655b7"
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/plugins/ipam/host-local",
|
||||
"Rev": "88377fa3466eea30817b038c69ac06686e7655b7"
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/plugins/main/bridge",
|
||||
"Rev": "88377fa3466eea30817b038c69ac06686e7655b7"
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/plugins/main/ipvlan",
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/plugins/main/macvlan",
|
||||
"Rev": "88377fa3466eea30817b038c69ac06686e7655b7"
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/cni/plugins/main/veth",
|
||||
"Rev": "88377fa3466eea30817b038c69ac06686e7655b7"
|
||||
"Rev": "49a018fa85ac216fdc76c835371807bdcf3b8ead"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/appc/docker2aci/lib",
|
||||
|
||||
+51
-23
@@ -15,7 +15,7 @@
|
||||
package ip
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func makeVeth(name, peer string, mtu int) (netlink.Link, error) {
|
||||
func makeVethPair(name, peer string, mtu int) (netlink.Link, error) {
|
||||
veth := &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: name,
|
||||
@@ -39,33 +39,50 @@ func makeVeth(name, peer string, mtu int) (netlink.Link, error) {
|
||||
return veth, nil
|
||||
}
|
||||
|
||||
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):
|
||||
continue
|
||||
|
||||
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(entropy string) string {
|
||||
h := sha512.New()
|
||||
h.Write([]byte(entropy))
|
||||
return fmt.Sprintf("veth%x", h.Sum(nil)[:5])
|
||||
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
|
||||
}
|
||||
|
||||
// SetupVeth sets up a virtual ethernet link.
|
||||
// Should be in container netns.
|
||||
// TODO(eyakubovich): get rid of entropy and ask kernel to pick name via pattern
|
||||
func SetupVeth(entropy, contVethName string, mtu int, hostNS *os.File) (hostVeth, contVeth netlink.Link, err error) {
|
||||
// NetworkManager (recent versions) will ignore veth devices that start with "veth"
|
||||
hostVethName := RandomVethName(entropy)
|
||||
hostVeth, err = makeVeth(hostVethName, contVethName, mtu)
|
||||
func SetupVeth(contVethName string, mtu int, hostNS *os.File) (hostVeth, contVeth netlink.Link, err error) {
|
||||
var hostVethName string
|
||||
hostVethName, contVeth, err = makeVeth(contVethName, mtu)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to make veth pair: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetUp(hostVeth); err != nil {
|
||||
err = fmt.Errorf("failed to set %q up: %v", hostVethName, err)
|
||||
return
|
||||
}
|
||||
|
||||
contVeth, err = netlink.LinkByName(contVethName)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to lookup %q: %v", contVethName, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -74,6 +91,17 @@ func SetupVeth(entropy, contVethName string, mtu int, hostNS *os.File) (hostVeth
|
||||
return
|
||||
}
|
||||
|
||||
hostVeth, err = netlink.LinkByName(hostVethName)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to lookup %q: %v", hostVethName, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetUp(hostVeth); err != nil {
|
||||
err = fmt.Errorf("failed to set %q up: %v", contVethName, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetNsFd(hostVeth, int(hostNS.Fd())); err != nil {
|
||||
err = fmt.Errorf("failed to move veth to host netns: %v", err)
|
||||
return
|
||||
|
||||
+11
-2
@@ -124,9 +124,18 @@ func ConfigureIface(ifName string, res *Result) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrintResult writes out prettified Result to stdout
|
||||
// PrintResult writes out prettified Result JSON to stdout
|
||||
func PrintResult(res *Result) error {
|
||||
data, err := json.MarshalIndent(res, "", " ")
|
||||
return prettyPrint(res)
|
||||
}
|
||||
|
||||
// PrintError writes out prettified Error JSON to stdout
|
||||
func PrintError(err *Error) error {
|
||||
return prettyPrint(err)
|
||||
}
|
||||
|
||||
func prettyPrint(obj interface{}) error {
|
||||
data, err := json.MarshalIndent(obj, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+6
@@ -48,6 +48,12 @@ type Route struct {
|
||||
GW net.IP
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
Code uint `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Details string `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// net.IPNet is not JSON (un)marshallable so this duality is needed
|
||||
// for our custom ip.IPNet type
|
||||
|
||||
|
||||
+15
-7
@@ -17,9 +17,12 @@
|
||||
package skel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/pkg/plugin"
|
||||
)
|
||||
|
||||
// CmdArgs captures all the arguments passed in to the plugin
|
||||
@@ -61,13 +64,12 @@ func PluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error) {
|
||||
}
|
||||
|
||||
if argsMissing {
|
||||
os.Exit(1)
|
||||
die("required env variables missing")
|
||||
}
|
||||
|
||||
stdinData, err := ioutil.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
log.Printf("Error reading from stdin: %v", err)
|
||||
os.Exit(1)
|
||||
die("error reading from stdin: %v", err)
|
||||
}
|
||||
|
||||
cmdArgs := &CmdArgs{
|
||||
@@ -87,12 +89,18 @@ func PluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error) {
|
||||
err = cmdDel(cmdArgs)
|
||||
|
||||
default:
|
||||
log.Printf("Unknown CNI_COMMAND: %v", cmd)
|
||||
os.Exit(1)
|
||||
die("unknown CNI_COMMAND: %v", cmd)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("%v: %v", cmd, err)
|
||||
os.Exit(1)
|
||||
die(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func die(f string, args ...interface{}) {
|
||||
plugin.PrintError(&plugin.Error{
|
||||
Code: 100,
|
||||
Msg: fmt.Sprintf(f, args...),
|
||||
})
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
+3
-3
@@ -47,9 +47,9 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
|
||||
switch ipamConf.Type {
|
||||
case "host-local":
|
||||
ipConf, err = allocator.Get(args.Netns)
|
||||
ipConf, err = allocator.Get(args.ContainerID)
|
||||
case "host-local-ptp":
|
||||
ipConf, err = allocator.GetPtP(args.Netns)
|
||||
ipConf, err = allocator.GetPtP(args.ContainerID)
|
||||
default:
|
||||
return errors.New("Unsupported IPAM plugin type")
|
||||
}
|
||||
@@ -80,5 +80,5 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return allocator.Release(args.Netns)
|
||||
return allocator.Release(args.ContainerID)
|
||||
}
|
||||
|
||||
+1
-1
@@ -130,7 +130,7 @@ func setupVeth(netns string, br *netlink.Bridge, ifName string, mtu int, pr *plu
|
||||
|
||||
err := ns.WithNetNSPath(netns, func(hostNS *os.File) error {
|
||||
// create the veth pair in the container and move host end into host netns
|
||||
hostVeth, _, err := ip.SetupVeth(netns, ifName, mtu, hostNS)
|
||||
hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/pkg/ip"
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/pkg/ns"
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/pkg/plugin"
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/pkg/skel"
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
type NetConf struct {
|
||||
plugin.NetConf
|
||||
Master string `json:"master"`
|
||||
Mode string `json:"mode"`
|
||||
IPMasq bool `json:"ipMasq"`
|
||||
MTU int `json:"mtu"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
// this ensures that main runs only on main thread (thread group leader).
|
||||
// since namespace ops (unshare, setns) are done for a single thread, we
|
||||
// must ensure that the goroutine does not jump from OS thread to thread
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
func loadConf(bytes []byte) (*NetConf, error) {
|
||||
n := &NetConf{}
|
||||
if err := json.Unmarshal(bytes, n); err != nil {
|
||||
return nil, fmt.Errorf("failed to load netconf: %v", err)
|
||||
}
|
||||
if n.Master == "" {
|
||||
return nil, fmt.Errorf(`"master" field is required. It specifies the host interface name to virtualize`)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func modeFromString(s string) (netlink.IPVlanMode, error) {
|
||||
switch s {
|
||||
case "":
|
||||
return netlink.IPVLAN_MODE_L2, nil
|
||||
case "l2":
|
||||
return netlink.IPVLAN_MODE_L2, nil
|
||||
case "l3":
|
||||
return netlink.IPVLAN_MODE_L3, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown ipvlan mode: %q", s)
|
||||
}
|
||||
}
|
||||
|
||||
func createIpvlan(conf *NetConf, ifName string, netns *os.File) error {
|
||||
mode, err := modeFromString(conf.Mode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m, err := netlink.LinkByName(conf.Master)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to lookup master %q: %v", conf.Master, err)
|
||||
}
|
||||
|
||||
mv := &netlink.IPVlan{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
MTU: conf.MTU,
|
||||
Name: ifName,
|
||||
ParentIndex: m.Attrs().Index,
|
||||
Namespace: netlink.NsFd(int(netns.Fd())),
|
||||
},
|
||||
Mode: mode,
|
||||
}
|
||||
|
||||
if err := netlink.LinkAdd(mv); err != nil {
|
||||
return fmt.Errorf("failed to create ipvlan: %v", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func cmdAdd(args *skel.CmdArgs) error {
|
||||
n, err := loadConf(args.StdinData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
netns, err := os.Open(args.Netns)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open netns %q: %v", netns, err)
|
||||
}
|
||||
defer netns.Close()
|
||||
|
||||
tmpName, err := ip.RandomVethName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = createIpvlan(n, tmpName, netns); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// run the IPAM plugin and get back the config to apply
|
||||
result, err := plugin.ExecAdd(n.IPAM.Type, args.StdinData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.IP4 == nil {
|
||||
return errors.New("IPAM plugin returned missing IPv4 config")
|
||||
}
|
||||
|
||||
err = ns.WithNetNS(netns, func(_ *os.File) error {
|
||||
err := renameLink(tmpName, args.IfName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rename ipvlan to %q: %v", args.IfName, err)
|
||||
}
|
||||
|
||||
return plugin.ConfigureIface(args.IfName, result)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n.IPMasq {
|
||||
chain := "CNI-" + n.Name
|
||||
if err = ip.SetupIPMasq(ip.Network(&result.IP4.IP), chain); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return plugin.PrintResult(result)
|
||||
}
|
||||
|
||||
func cmdDel(args *skel.CmdArgs) error {
|
||||
n, err := loadConf(args.StdinData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = plugin.ExecDel(n.IPAM.Type, args.StdinData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ns.WithNetNSPath(args.Netns, func(hostNS *os.File) error {
|
||||
return ip.DelLinkByName(args.IfName)
|
||||
})
|
||||
}
|
||||
|
||||
func renameLink(curName, newName string) error {
|
||||
link, err := netlink.LinkByName(curName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return netlink.LinkSetName(link, newName)
|
||||
}
|
||||
|
||||
func main() {
|
||||
skel.PluginMain(cmdAdd, cmdDel)
|
||||
}
|
||||
+5
-1
@@ -111,7 +111,11 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
defer netns.Close()
|
||||
|
||||
tmpName := ip.RandomVethName(args.Netns)
|
||||
tmpName, err := ip.RandomVethName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = createMacvlan(n, tmpName, netns); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+3
-5
@@ -46,9 +46,7 @@ type NetConf struct {
|
||||
func setupContainerVeth(netns, ifName string, mtu int, pr *plugin.Result) (string, error) {
|
||||
var hostVethName string
|
||||
err := ns.WithNetNSPath(netns, func(hostNS *os.File) error {
|
||||
entropy := netns + ifName
|
||||
|
||||
hostVeth, _, err := ip.SetupVeth(entropy, ifName, mtu, hostNS)
|
||||
hostVeth, _, err := ip.SetupVeth(ifName, mtu, hostNS)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -115,7 +113,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
|
||||
if conf.IPMasq {
|
||||
h := sha512.Sum512([]byte(args.Netns))
|
||||
h := sha512.Sum512([]byte(args.ContainerID))
|
||||
chain := fmt.Sprintf("CNI-%s-%x", conf.Name, h[:8])
|
||||
if err = ip.SetupIPMasq(&result.IP4.IP, chain); err != nil {
|
||||
return err
|
||||
@@ -142,7 +140,7 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
|
||||
if conf.IPMasq {
|
||||
h := sha512.Sum512([]byte(args.Netns))
|
||||
h := sha512.Sum512([]byte(args.ContainerID))
|
||||
chain := fmt.Sprintf("CNI-%s-%x", conf.Name, h[:8])
|
||||
if err = ip.TeardownIPMasq(ipn, chain); err != nil {
|
||||
return err
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
import (
|
||||
_ "github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/plugins/ipam/host-local"
|
||||
_ "github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/plugins/main/bridge"
|
||||
_ "github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/plugins/main/ipvlan"
|
||||
_ "github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/plugins/main/macvlan"
|
||||
_ "github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/plugins/main/veth"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user