2017-07-21 12:37:50 +00:00
|
|
|
// Copyright (c) 2017 Intel Corporation
|
2016-12-13 14:48:12 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2017-07-21 12:37:50 +00:00
|
|
|
// This is a "Multi-plugin".The delegate concept refered from CNI project
|
2016-12-13 14:48:12 +00:00
|
|
|
// It reads other plugin netconf, and then invoke them, e.g.
|
|
|
|
// flannel or sriov plugin.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"github.com/containernetworking/cni/pkg/invoke"
|
2018-05-09 06:33:44 +00:00
|
|
|
"github.com/containernetworking/cni/pkg/ns"
|
2016-12-13 14:48:12 +00:00
|
|
|
"github.com/containernetworking/cni/pkg/skel"
|
2018-05-01 18:08:39 +00:00
|
|
|
cnitypes "github.com/containernetworking/cni/pkg/types"
|
2017-06-29 16:19:09 +00:00
|
|
|
"github.com/containernetworking/cni/pkg/version"
|
2018-05-01 18:08:39 +00:00
|
|
|
k8s "github.com/intel/multus-cni/k8sclient"
|
|
|
|
"github.com/intel/multus-cni/types"
|
2018-05-09 06:33:44 +00:00
|
|
|
"github.com/vishvananda/netlink"
|
2016-12-13 14:48:12 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func saveScratchNetConf(containerID, dataDir string, netconf []byte) error {
|
|
|
|
if err := os.MkdirAll(dataDir, 0700); err != nil {
|
|
|
|
return fmt.Errorf("failed to create the multus data directory(%q): %v", dataDir, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
path := filepath.Join(dataDir, containerID)
|
|
|
|
|
|
|
|
err := ioutil.WriteFile(path, netconf, 0600)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to write container data in the path(%q): %v", path, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func consumeScratchNetConf(containerID, dataDir string) ([]byte, error) {
|
|
|
|
path := filepath.Join(dataDir, containerID)
|
|
|
|
defer os.Remove(path)
|
|
|
|
|
2017-11-09 17:55:37 +00:00
|
|
|
return ioutil.ReadFile(path)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
func getIfname(delegate *types.DelegateNetConf, argif string, idx int) string {
|
|
|
|
if delegate.IfnameRequest != "" {
|
|
|
|
return delegate.IfnameRequest
|
|
|
|
}
|
|
|
|
if delegate.MasterPlugin {
|
|
|
|
// master plugin always uses the CNI-provided interface name
|
|
|
|
return argif
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
// Otherwise construct a unique interface name from the delegate's
|
|
|
|
// position in the delegate list
|
|
|
|
return fmt.Sprintf("net%d", idx)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
func saveDelegates(containerID, dataDir string, delegates []*types.DelegateNetConf) error {
|
2016-12-13 14:48:12 +00:00
|
|
|
delegatesBytes, err := json.Marshal(delegates)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error serializing delegate netconf: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = saveScratchNetConf(containerID, dataDir, delegatesBytes); err != nil {
|
|
|
|
return fmt.Errorf("error in saving the delegates : %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-09 06:33:44 +00:00
|
|
|
func validateIfName(nsname string, ifname string) error {
|
|
|
|
podNs, err := ns.GetNS(nsname)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("no netns: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = podNs.Do(func(_ ns.NetNS) error {
|
|
|
|
_, err := netlink.LinkByName(ifname)
|
|
|
|
if err != nil {
|
|
|
|
if err.Error() == "Link not found" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return fmt.Errorf("ifname %s is already exist", ifname)
|
|
|
|
})
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
func delegateAdd(ifName string, delegate *types.DelegateNetConf) (cnitypes.Result, error) {
|
|
|
|
if os.Setenv("CNI_IFNAME", ifName) != nil {
|
|
|
|
return nil, fmt.Errorf("Multus: error in setting CNI_IFNAME")
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
if err := validateIfName(os.Getenv("CNI_NETNS"), ifName); err != nil {
|
|
|
|
return nil, fmt.Errorf("cannot set %q ifname to %q: %v", delegate.Type, ifName, err)
|
2018-05-09 06:33:44 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
result, err := invoke.DelegateAdd(delegate.Type, delegate.Bytes)
|
2016-12-13 14:48:12 +00:00
|
|
|
if err != nil {
|
2018-05-01 18:08:39 +00:00
|
|
|
return nil, fmt.Errorf("Multus: error in invoke Delegate add - %q: %v", delegate.Type, err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
return result, nil
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
func delegateDel(ifName string, delegateConf *types.DelegateNetConf) error {
|
|
|
|
if os.Setenv("CNI_IFNAME", ifName) != nil {
|
|
|
|
return fmt.Errorf("Multus: error in setting CNI_IFNAME")
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
if err := invoke.DelegateDel(delegateConf.Type, delegateConf.Bytes); err != nil {
|
|
|
|
return fmt.Errorf("Multus: error in invoke Delegate del - %q: %v", delegateConf.Type, err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
return nil
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
func delPlugins(argIfname string, delegates []*types.DelegateNetConf, lastIdx int) error {
|
2017-02-21 19:01:58 +00:00
|
|
|
if os.Setenv("CNI_COMMAND", "DEL") != nil {
|
|
|
|
return fmt.Errorf("Multus: error in setting CNI_COMMAND to DEL")
|
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
for idx := lastIdx; idx >= 0; idx-- {
|
|
|
|
ifName := getIfname(delegates[idx], argIfname, idx)
|
|
|
|
if err := delegateDel(ifName, delegates[idx]); err != nil {
|
|
|
|
return err
|
2017-02-21 19:01:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-12-13 14:48:12 +00:00
|
|
|
func cmdAdd(args *skel.CmdArgs) error {
|
2017-08-11 16:24:43 +00:00
|
|
|
var nopodnet bool
|
2018-05-01 18:08:39 +00:00
|
|
|
n, err := types.LoadNetConf(args.StdinData)
|
2016-12-13 14:48:12 +00:00
|
|
|
if err != nil {
|
2017-08-11 16:24:43 +00:00
|
|
|
return fmt.Errorf("err in loading netconf: %v", err)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2017-06-29 16:19:09 +00:00
|
|
|
if n.Kubeconfig != "" {
|
2018-05-01 18:08:39 +00:00
|
|
|
delegates, err := k8s.GetK8sNetwork(args, n.Kubeconfig, n.ConfDir)
|
2017-12-02 17:20:09 +00:00
|
|
|
if err != nil {
|
2018-04-20 17:30:12 +00:00
|
|
|
if _, ok := err.(*k8s.NoK8sNetworkError); ok {
|
2017-12-02 17:20:09 +00:00
|
|
|
nopodnet = true
|
2018-05-01 18:08:39 +00:00
|
|
|
} else {
|
2017-12-02 17:20:09 +00:00
|
|
|
return fmt.Errorf("Multus: Err in getting k8s network from pod: %v", err)
|
2017-08-11 16:24:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
if err = n.AddDelegates(delegates); err != nil {
|
|
|
|
return err
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-11 16:24:43 +00:00
|
|
|
if n.Kubeconfig == "" || nopodnet {
|
2017-06-29 16:19:09 +00:00
|
|
|
if err := saveDelegates(args.ContainerID, n.CNIDir, n.Delegates); err != nil {
|
|
|
|
return fmt.Errorf("Multus: Err in saving the delegates: %v", err)
|
|
|
|
}
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
var result, tmpResult cnitypes.Result
|
|
|
|
lastIdx := 0
|
|
|
|
for idx, delegate := range n.Delegates {
|
|
|
|
lastIdx = idx
|
|
|
|
ifName := getIfname(delegate, args.IfName, idx)
|
|
|
|
tmpResult, err = delegateAdd(ifName, delegate)
|
|
|
|
if err != nil {
|
|
|
|
break
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
// Master plugin result is always used if present
|
|
|
|
if delegate.MasterPlugin || result == nil {
|
|
|
|
result = tmpResult
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
}
|
2018-05-01 18:08:39 +00:00
|
|
|
if err != nil {
|
|
|
|
// Ignore errors; DEL must be idempotent anyway
|
|
|
|
_ = delPlugins(args.IfName, n.Delegates, lastIdx)
|
|
|
|
return err
|
|
|
|
}
|
2016-12-13 14:48:12 +00:00
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
return result.Print()
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func cmdDel(args *skel.CmdArgs) error {
|
2017-08-11 16:24:43 +00:00
|
|
|
var nopodnet bool
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
in, err := types.LoadNetConf(args.StdinData)
|
2016-12-13 14:48:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-06-29 16:19:09 +00:00
|
|
|
if in.Kubeconfig != "" {
|
2018-05-01 18:08:39 +00:00
|
|
|
delegates, r := k8s.GetK8sNetwork(args, in.Kubeconfig, in.ConfDir)
|
2018-04-23 06:51:11 +00:00
|
|
|
if r != nil {
|
|
|
|
if _, ok := r.(*k8s.NoK8sNetworkError); ok {
|
|
|
|
nopodnet = true
|
|
|
|
} else {
|
|
|
|
return fmt.Errorf("Multus: Err in getting k8s network from pod: %v", r)
|
2017-08-11 16:24:43 +00:00
|
|
|
}
|
2017-06-29 16:19:09 +00:00
|
|
|
}
|
2016-12-13 14:48:12 +00:00
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
if err = in.AddDelegates(delegates); err != nil {
|
|
|
|
return err
|
2017-08-11 16:24:43 +00:00
|
|
|
}
|
|
|
|
}
|
2017-06-29 16:19:09 +00:00
|
|
|
|
2017-08-11 16:24:43 +00:00
|
|
|
if in.Kubeconfig == "" || nopodnet {
|
2017-06-29 16:19:09 +00:00
|
|
|
netconfBytes, err := consumeScratchNetConf(args.ContainerID, in.CNIDir)
|
|
|
|
if err != nil {
|
2017-11-09 17:55:37 +00:00
|
|
|
if os.IsNotExist(err) {
|
|
|
|
// Per spec should ignore error if resources are missing / already removed
|
|
|
|
return nil
|
|
|
|
}
|
2017-06-29 16:19:09 +00:00
|
|
|
return fmt.Errorf("Multus: Err in reading the delegates: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-09-28 14:42:56 +00:00
|
|
|
if err := json.Unmarshal(netconfBytes, &in.Delegates); err != nil {
|
2017-06-29 16:19:09 +00:00
|
|
|
return fmt.Errorf("Multus: failed to load netconf: %v", err)
|
|
|
|
}
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 18:08:39 +00:00
|
|
|
return delPlugins(args.IfName, in.Delegates, len(in.Delegates)-1)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
2017-06-29 16:19:09 +00:00
|
|
|
skel.PluginMain(cmdAdd, cmdDel, version.All)
|
2016-12-13 14:48:12 +00:00
|
|
|
}
|