Drop OCICNI dependency

We do not use the ocicni code anymore so let's get rid of it. Only the
port struct is used but we can copy this into libpod network types so
we can debloat the binary.

The next step is to remove the OCICNI port mapping form the container
config and use the better PortMapping struct everywhere.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger
2021-08-24 23:04:25 +02:00
parent 85e8fbf7f3
commit b906b9d858
26 changed files with 59 additions and 1482 deletions

View File

@ -8,8 +8,8 @@ import (
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
@ -73,7 +73,7 @@ func port(_ *cobra.Command, args []string) error {
var (
container string
err error
userPort ocicni.PortMapping
userPort types.OCICNIPortMapping
)
if len(args) == 0 && !portOpts.Latest && !portOpts.All {
@ -105,7 +105,7 @@ func port(_ *cobra.Command, args []string) error {
if err != nil {
return err
}
userPort = ocicni.PortMapping{
userPort = types.OCICNIPortMapping{
HostPort: 0,
ContainerPort: int32(portNum),
Protocol: fields[1],

View File

@ -15,8 +15,8 @@ import (
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/utils"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -469,7 +469,7 @@ func (l psReporter) UTS() string {
// portsToString converts the ports used to a string of the from "port1, port2"
// and also groups a continuous list of ports into a readable format.
func portsToString(ports []ocicni.PortMapping) string {
func portsToString(ports []types.OCICNIPortMapping) string {
if len(ports) == 0 {
return ""
}
@ -478,8 +478,8 @@ func portsToString(ports []ocicni.PortMapping) string {
return comparePorts(ports[i], ports[j])
})
portGroups := [][]ocicni.PortMapping{}
currentGroup := []ocicni.PortMapping{}
portGroups := [][]types.OCICNIPortMapping{}
currentGroup := []types.OCICNIPortMapping{}
for i, v := range ports {
var prevPort, nextPort *int32
if i > 0 {
@ -492,17 +492,17 @@ func portsToString(ports []ocicni.PortMapping) string {
port := v.ContainerPort
// Helper functions
addToCurrentGroup := func(x ocicni.PortMapping) {
addToCurrentGroup := func(x types.OCICNIPortMapping) {
currentGroup = append(currentGroup, x)
}
addToPortGroup := func(x ocicni.PortMapping) {
portGroups = append(portGroups, []ocicni.PortMapping{x})
addToPortGroup := func(x types.OCICNIPortMapping) {
portGroups = append(portGroups, []types.OCICNIPortMapping{x})
}
finishCurrentGroup := func() {
portGroups = append(portGroups, currentGroup)
currentGroup = []ocicni.PortMapping{}
currentGroup = []types.OCICNIPortMapping{}
}
// Single entry slice
@ -600,7 +600,7 @@ func portsToString(ports []ocicni.PortMapping) string {
return strings.Join(portDisplay, ", ")
}
func comparePorts(i, j ocicni.PortMapping) bool {
func comparePorts(i, j types.OCICNIPortMapping) bool {
if i.ContainerPort != j.ContainerPort {
return i.ContainerPort < j.ContainerPort
}

1
go.mod
View File

@ -20,7 +20,6 @@ require (
github.com/containers/storage v1.36.0
github.com/coreos/go-systemd/v22 v22.3.2
github.com/coreos/stream-metadata-go v0.0.0-20210225230131-70edb9eb47b3
github.com/cri-o/ocicni v0.2.1-0.20210621164014-d0acc7862283
github.com/cyphar/filepath-securejoin v0.2.3
github.com/davecgh/go-spew v1.1.1
github.com/digitalocean/go-qemu v0.0.0-20210209191958-152a1535e49f

5
go.sum
View File

@ -241,7 +241,6 @@ github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ
github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI=
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CYwm0dHzbz0XEjofx0uB0=
github.com/containernetworking/plugins v0.9.1 h1:FD1tADPls2EEi3flPc2OegIY1M9pUa9r2Quag7HMLV8=
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
github.com/containers/buildah v1.23.0 h1:qGIeSNOczUHzvnaaOS29HSMiYAjw6JgIXYksAyvqnLs=
@ -291,8 +290,6 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cri-o/ocicni v0.2.1-0.20210621164014-d0acc7862283 h1:7FyIYKksGvRF8XjMkG5T6uIxg8PcgZoPyO+f6kHT5+s=
github.com/cri-o/ocicni v0.2.1-0.20210621164014-d0acc7862283/go.mod h1:vingr1ztOAzP2WyTgGbpMov9dFhbjNxdLtDv0+PhAvY=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
@ -701,7 +698,6 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -712,7 +708,6 @@ github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=

View File

@ -10,7 +10,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/lock"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/opencontainers/runtime-tools/generate"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -41,7 +41,7 @@ func getTestContainer(id, name string, manager lock.Manager) (*Container, error)
ContainerNetworkConfig: ContainerNetworkConfig{
DNSServer: []net.IP{net.ParseIP("192.168.1.1"), net.ParseIP("192.168.2.2")},
DNSSearch: []string{"example.com", "example.example.com"},
PortMappings: []ocicni.PortMapping{
PortMappings: []types.OCICNIPortMapping{
{
HostPort: 80,
ContainerPort: 90,

View File

@ -16,7 +16,6 @@ import (
"github.com/containers/podman/v3/libpod/network/cni"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -461,7 +460,7 @@ func (c *Container) NewNetNS() bool {
// PortMappings returns the ports that will be mapped into a container if
// a new network namespace is created
// If NewNetNS() is false, this value is unused
func (c *Container) PortMappings() ([]ocicni.PortMapping, error) {
func (c *Container) PortMappings() ([]types.OCICNIPortMapping, error) {
// First check if the container belongs to a network namespace (like a pod)
if len(c.config.NetNsCtr) > 0 {
netNsCtr, err := c.runtime.GetContainer(c.config.NetNsCtr)

View File

@ -6,9 +6,9 @@ import (
"github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
)
@ -230,7 +230,7 @@ type ContainerNetworkConfig struct {
// PortMappings are the ports forwarded to the container's network
// namespace
// These are not used unless CreateNetNS is true
PortMappings []ocicni.PortMapping `json:"portMappings,omitempty"`
PortMappings []types.OCICNIPortMapping `json:"portMappings,omitempty"`
// ExposedPorts are the ports which are exposed but not forwarded
// into the container.
// The map key is the port and the string slice contains the protocols,

View File

@ -10,11 +10,11 @@ import (
"time"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/lookup"
"github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
@ -544,7 +544,7 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNS
// ocicniPortMappingToContainerPort takes an ocicni portmapping and converts
// it to a v1.ContainerPort format for kube output
func ocicniPortMappingToContainerPort(portMappings []ocicni.PortMapping) ([]v1.ContainerPort, error) {
func ocicniPortMappingToContainerPort(portMappings []types.OCICNIPortMapping) ([]v1.ContainerPort, error) {
containerPorts := make([]v1.ContainerPort, 0, len(portMappings))
for _, p := range portMappings {
var protocol v1.Protocol

View File

@ -199,6 +199,20 @@ type PortMapping struct {
Protocol string `json:"protocol,omitempty"`
}
// OCICNIPortMapping maps to the standard CNI portmapping Capability.
// Deprecated, do not use this struct for new fields. This only exists
// for backwards compatibility.
type OCICNIPortMapping struct {
// HostPort is the port number on the host.
HostPort int32 `json:"hostPort"`
// ContainerPort is the port number inside the sandbox.
ContainerPort int32 `json:"containerPort"`
// Protocol is the protocol of the port mapping.
Protocol string `json:"protocol"`
// HostIP is the host ip to use.
HostIP string `json:"hostIP"`
}
type SetupOptions struct {
NetworkOptions
}

View File

@ -27,7 +27,6 @@ import (
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage/pkg/lockfile"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -927,7 +926,8 @@ func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) {
return nil, nil
}
err := ns.WithNetNSPath(netNSPath, func(_ ns.NetNS) error {
link, err := netlink.LinkByName(ocicni.DefaultInterfaceName)
// FIXME get the interface from the container netstatus
link, err := netlink.LinkByName("eth0")
if err != nil {
return err
}
@ -1315,7 +1315,7 @@ func (r *Runtime) normalizeNetworkName(nameOrID string) (string, error) {
return net.Name, nil
}
func ocicniPortsToNetTypesPorts(ports []ocicni.PortMapping) []types.PortMapping {
func ocicniPortsToNetTypesPorts(ports []types.OCICNIPortMapping) []types.PortMapping {
newPorts := make([]types.PortMapping, 0, len(ports))
for _, port := range ports {
newPorts = append(newPorts, types.PortMapping{

View File

@ -9,7 +9,7 @@ import (
"time"
"github.com/containers/podman/v3/libpod/define"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@ -32,7 +32,7 @@ func createUnitName(prefix string, name string) string {
}
// Bind ports to keep them closed on the host
func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
func bindPorts(ports []types.OCICNIPortMapping) ([]*os.File, error) {
var files []*os.File
notifySCTP := false
for _, i := range ports {

View File

@ -14,14 +14,13 @@ import (
"github.com/containers/image/v5/types"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/events"
netTypes "github.com/containers/podman/v3/libpod/network/types"
nettypes "github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/namespaces"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage"
"github.com/containers/storage/pkg/idtools"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/opencontainers/runtime-tools/generate"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -1040,7 +1039,7 @@ func WithDependencyCtrs(ctrs []*Container) CtrCreateOption {
// namespace with a minimal configuration.
// An optional array of port mappings can be provided.
// Conflicts with WithNetNSFrom().
func WithNetNS(portMappings []ocicni.PortMapping, exposedPorts map[uint16][]string, postConfigureNetNS bool, netmode string, networks []string) CtrCreateOption {
func WithNetNS(portMappings []nettypes.OCICNIPortMapping, exposedPorts map[uint16][]string, postConfigureNetNS bool, netmode string, networks []string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
@ -2063,10 +2062,10 @@ func WithInfraContainer() PodCreateOption {
}
// WithInfraContainerPorts tells the pod to add port bindings to the pause container
func WithInfraContainerPorts(bindings []ocicni.PortMapping, infraSpec *specgen.SpecGenerator) []netTypes.PortMapping {
bindingSpec := []netTypes.PortMapping{}
func WithInfraContainerPorts(bindings []nettypes.OCICNIPortMapping, infraSpec *specgen.SpecGenerator) []nettypes.PortMapping {
bindingSpec := []nettypes.PortMapping{}
for _, bind := range bindings {
currBind := netTypes.PortMapping{}
currBind := nettypes.PortMapping{}
currBind.ContainerPort = uint16(bind.ContainerPort)
currBind.HostIP = bind.HostIP
currBind.HostPort = uint16(bind.HostPort)

View File

@ -15,8 +15,8 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/utils"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/fsnotify/fsnotify"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
@ -295,8 +295,8 @@ func writeHijackHeader(r *http.Request, conn io.Writer) {
}
// Convert OCICNI port bindings into Inspect-formatted port bindings.
func makeInspectPortBindings(bindings []ocicni.PortMapping, expose map[uint16][]string) map[string][]define.InspectHostPort {
portBindings := make(map[string][]define.InspectHostPort, len(bindings))
func makeInspectPortBindings(bindings []types.OCICNIPortMapping, expose map[uint16][]string) map[string][]define.InspectHostPort {
portBindings := make(map[string][]define.InspectHostPort)
for _, port := range bindings {
key := fmt.Sprintf("%d/%s", port.ContainerPort, port.Protocol)
hostPorts := portBindings[key]

View File

@ -5,8 +5,8 @@ import (
"strings"
"time"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/ps/define"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
)
@ -54,7 +54,7 @@ type ListContainer struct {
// boolean to be set
PodName string
// Port mappings
Ports []ocicni.PortMapping
Ports []types.OCICNIPortMapping
// Size of the container rootfs. Requires the size boolean to be true
Size *define.ContainerSize
// Time when container started

View File

@ -11,7 +11,6 @@ import (
nettypes "github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/storage/pkg/archive"
"github.com/cri-o/ocicni/pkg/ocicni"
)
// ContainerRunlabelOptions are the options to execute container-runlabel.
@ -422,7 +421,7 @@ type ContainerPortOptions struct {
// the CLI to output ports
type ContainerPortReport struct {
Id string //nolint
Ports []ocicni.PortMapping
Ports []nettypes.OCICNIPortMapping
}
// ContainerCpOptions describes input options for cp.

View File

@ -23,8 +23,8 @@ import (
"path/filepath"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/storage/pkg/reexec"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
rkport "github.com/rootless-containers/rootlesskit/pkg/port"
rkbuiltin "github.com/rootless-containers/rootlesskit/pkg/port/builtin"
@ -44,7 +44,7 @@ const (
// Config needs to be provided to the process via stdin as a JSON string.
// stdin needs to be closed after the message has been written.
type Config struct {
Mappings []ocicni.PortMapping
Mappings []types.OCICNIPortMapping
NetNSPath string
ExitFD int
ReadyFD int
@ -313,7 +313,7 @@ func handler(ctx context.Context, conn io.Reader, pm rkport.Manager) error {
return nil
}
func exposePorts(pm rkport.Manager, portMappings []ocicni.PortMapping, childIP string) error {
func exposePorts(pm rkport.Manager, portMappings []types.OCICNIPortMapping, childIP string) error {
ctx := context.TODO()
for _, i := range portMappings {
hostIP := i.HostIP

View File

@ -11,7 +11,6 @@ import (
"github.com/containers/podman/v3/utils"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@ -25,11 +24,11 @@ const (
// Parse port maps to OCICNI port mappings.
// Returns a set of OCICNI port mappings, and maps of utilized container and
// host ports.
func ParsePortMapping(portMappings []types.PortMapping) ([]ocicni.PortMapping, map[string]map[string]map[uint16]uint16, map[string]map[string]map[uint16]uint16, error) {
func ParsePortMapping(portMappings []types.PortMapping) ([]types.OCICNIPortMapping, map[string]map[string]map[uint16]uint16, map[string]map[string]map[uint16]uint16, error) {
// First, we need to validate the ports passed in the specgen, and then
// convert them into CNI port mappings.
type tempMapping struct {
mapping ocicni.PortMapping
mapping types.OCICNIPortMapping
startOfRange bool
isInRange bool
}
@ -159,7 +158,7 @@ func ParsePortMapping(portMappings []types.PortMapping) ([]ocicni.PortMapping, m
// struct.
// Don't use hostIP - we want to preserve the
// empty string hostIP by default for compat.
cniPort := ocicni.PortMapping{
cniPort := types.OCICNIPortMapping{
HostPort: int32(hPort),
ContainerPort: int32(cPort),
Protocol: p,
@ -179,7 +178,7 @@ func ParsePortMapping(portMappings []types.PortMapping) ([]ocicni.PortMapping, m
// Handle any 0 host ports now by setting random container ports.
if postAssignHostPort {
remadeMappings := make([]ocicni.PortMapping, 0, len(tempMappings))
remadeMappings := make([]types.OCICNIPortMapping, 0, len(tempMappings))
var (
candidate int
@ -245,7 +244,7 @@ func ParsePortMapping(portMappings []types.PortMapping) ([]ocicni.PortMapping, m
return remadeMappings, containerPortValidate, hostPortValidate, nil
}
finalMappings := []ocicni.PortMapping{}
finalMappings := []types.OCICNIPortMapping{}
for _, m := range tempMappings {
finalMappings = append(finalMappings, m.mapping)
}
@ -254,7 +253,7 @@ func ParsePortMapping(portMappings []types.PortMapping) ([]ocicni.PortMapping, m
}
// Make final port mappings for the container
func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData *libimage.ImageData) ([]ocicni.PortMapping, map[uint16][]string, error) {
func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData *libimage.ImageData) ([]types.OCICNIPortMapping, map[uint16][]string, error) {
finalMappings, containerPortValidate, hostPortValidate, err := ParsePortMapping(s.PortMappings)
if err != nil {
return nil, nil, err
@ -356,7 +355,7 @@ func createPortMappings(ctx context.Context, s *specgen.SpecGenerator, imageData
logrus.Debugf("Mapping exposed port %d/%s to host port %d", port, p, hostPort)
// Make a CNI port mapping
cniPort := ocicni.PortMapping{
cniPort := types.OCICNIPortMapping{
HostPort: int32(candidate),
ContainerPort: int32(port),
Protocol: p,

View File

@ -1,191 +0,0 @@
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
Copyright 2016 Red Hat, 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.

View File

@ -1,870 +0,0 @@
package ocicni
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"os"
"path"
"path/filepath"
"sort"
"strings"
"sync"
"github.com/containernetworking/cni/libcni"
cniinvoke "github.com/containernetworking/cni/pkg/invoke"
cnitypes "github.com/containernetworking/cni/pkg/types"
cnicurrent "github.com/containernetworking/cni/pkg/types/current"
cniversion "github.com/containernetworking/cni/pkg/version"
"github.com/fsnotify/fsnotify"
"github.com/sirupsen/logrus"
)
type cniNetworkPlugin struct {
cniConfig *libcni.CNIConfig
sync.RWMutex
defaultNetName netName
networks map[string]*cniNetwork
nsManager *nsManager
confDir string
binDirs []string
shutdownChan chan struct{}
watcher *fsnotify.Watcher
done *sync.WaitGroup
// The pod map provides synchronization for a given pod's network
// operations. Each pod's setup/teardown/status operations
// are synchronized against each other, but network operations of other
// pods can proceed in parallel.
podsLock sync.Mutex
pods map[string]*podLock
// For testcases
exec cniinvoke.Exec
cacheDir string
}
type netName struct {
name string
changeable bool
}
type cniNetwork struct {
name string
filePath string
config *libcni.NetworkConfigList
}
var errMissingDefaultNetwork = "No CNI configuration file in %s. Has your network provider started?"
type podLock struct {
// Count of in-flight operations for this pod; when this reaches zero
// the lock can be removed from the pod map
refcount uint
// Lock to synchronize operations for this specific pod
mu sync.Mutex
}
func buildFullPodName(podNetwork PodNetwork) string {
return podNetwork.Namespace + "_" + podNetwork.Name
}
// Lock network operations for a specific pod. If that pod is not yet in
// the pod map, it will be added. The reference count for the pod will
// be increased.
func (plugin *cniNetworkPlugin) podLock(podNetwork PodNetwork) *sync.Mutex {
plugin.podsLock.Lock()
defer plugin.podsLock.Unlock()
fullPodName := buildFullPodName(podNetwork)
lock, ok := plugin.pods[fullPodName]
if !ok {
lock = &podLock{}
plugin.pods[fullPodName] = lock
}
lock.refcount++
return &lock.mu
}
// Unlock network operations for a specific pod. The reference count for the
// pod will be decreased. If the reference count reaches zero, the pod will be
// removed from the pod map.
func (plugin *cniNetworkPlugin) podUnlock(podNetwork PodNetwork) {
plugin.podsLock.Lock()
defer plugin.podsLock.Unlock()
fullPodName := buildFullPodName(podNetwork)
lock, ok := plugin.pods[fullPodName]
if !ok {
logrus.Errorf("Cannot find reference in refcount map for %s. Refcount cannot be determined.", fullPodName)
return
} else if lock.refcount == 0 {
// This should never ever happen, but handle it anyway
delete(plugin.pods, fullPodName)
logrus.Errorf("Pod lock for %s still in map with zero refcount", fullPodName)
return
}
lock.refcount--
lock.mu.Unlock()
if lock.refcount == 0 {
delete(plugin.pods, fullPodName)
}
}
func newWatcher(confDir string) (*fsnotify.Watcher, error) {
// Ensure plugin directory exists, because the following monitoring logic
// relies on that.
if err := os.MkdirAll(confDir, 0755); err != nil {
return nil, fmt.Errorf("failed to create directory %q: %v", confDir, err)
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, fmt.Errorf("failed to create new watcher %v", err)
}
defer func() {
// Close watcher on error
if err != nil {
watcher.Close()
}
}()
if err = watcher.Add(confDir); err != nil {
return nil, fmt.Errorf("failed to add watch on %q: %v", confDir, err)
}
return watcher, nil
}
func (plugin *cniNetworkPlugin) monitorConfDir(start *sync.WaitGroup) {
start.Done()
plugin.done.Add(1)
defer plugin.done.Done()
for {
select {
case event := <-plugin.watcher.Events:
logrus.Infof("CNI monitoring event %v", event)
var defaultDeleted bool
createWrite := (event.Op&fsnotify.Create == fsnotify.Create ||
event.Op&fsnotify.Write == fsnotify.Write)
if event.Op&fsnotify.Remove == fsnotify.Remove {
// Care about the event if the default network
// was just deleted
defNet := plugin.getDefaultNetwork()
if defNet != nil && event.Name == defNet.filePath {
defaultDeleted = true
}
}
if !createWrite && !defaultDeleted {
continue
}
if err := plugin.syncNetworkConfig(); err != nil {
logrus.Errorf("CNI config loading failed, continue monitoring: %v", err)
continue
}
case err := <-plugin.watcher.Errors:
if err == nil {
continue
}
logrus.Errorf("CNI monitoring error %v", err)
return
case <-plugin.shutdownChan:
return
}
}
}
// InitCNI takes a binary directory in which to search for CNI plugins, and
// a configuration directory in which to search for CNI JSON config files.
// If no valid CNI configs exist, network requests will fail until valid CNI
// config files are present in the config directory.
// If defaultNetName is not empty, a CNI config with that network name will
// be used as the default CNI network, and container network operations will
// fail until that network config is present and valid.
// If defaultNetName is empty, CNI config files should be reloaded real-time and
// defaultNetName should be changeable and determined by file sorting.
func InitCNI(defaultNetName string, confDir string, binDirs ...string) (CNIPlugin, error) {
return initCNI(nil, "", defaultNetName, confDir, true, binDirs...)
}
// InitCNIWithCache works like InitCNI except that it takes the cni cache directory as third param.
func InitCNIWithCache(defaultNetName, confDir, cacheDir string, binDirs ...string) (CNIPlugin, error) {
return initCNI(nil, cacheDir, defaultNetName, confDir, true, binDirs...)
}
// InitCNINoInotify works like InitCNI except that it does not use inotify to watch for changes in the CNI config dir.
func InitCNINoInotify(defaultNetName, confDir, cacheDir string, binDirs ...string) (CNIPlugin, error) {
return initCNI(nil, cacheDir, defaultNetName, confDir, false, binDirs...)
}
// Internal function to allow faking out exec functions for testing
func initCNI(exec cniinvoke.Exec, cacheDir, defaultNetName string, confDir string, useInotify bool, binDirs ...string) (CNIPlugin, error) {
if confDir == "" {
confDir = DefaultConfDir
}
if len(binDirs) == 0 {
binDirs = []string{DefaultBinDir}
}
plugin := &cniNetworkPlugin{
cniConfig: libcni.NewCNIConfigWithCacheDir(binDirs, cacheDir, exec),
defaultNetName: netName{
name: defaultNetName,
// If defaultNetName is not assigned in initialization,
// it should be changeable
changeable: defaultNetName == "",
},
networks: make(map[string]*cniNetwork),
confDir: confDir,
binDirs: binDirs,
shutdownChan: make(chan struct{}),
done: &sync.WaitGroup{},
pods: make(map[string]*podLock),
exec: exec,
cacheDir: cacheDir,
}
if exec == nil {
exec = &cniinvoke.DefaultExec{
RawExec: &cniinvoke.RawExec{Stderr: os.Stderr},
PluginDecoder: cniversion.PluginDecoder{},
}
}
nsm, err := newNSManager()
if err != nil {
return nil, err
}
plugin.nsManager = nsm
plugin.syncNetworkConfig()
if useInotify {
plugin.watcher, err = newWatcher(plugin.confDir)
if err != nil {
return nil, err
}
startWg := sync.WaitGroup{}
startWg.Add(1)
go plugin.monitorConfDir(&startWg)
startWg.Wait()
}
return plugin, nil
}
func (plugin *cniNetworkPlugin) Shutdown() error {
close(plugin.shutdownChan)
if plugin.watcher != nil {
plugin.watcher.Close()
}
plugin.done.Wait()
return nil
}
func loadNetworks(confDir string, cni *libcni.CNIConfig) (map[string]*cniNetwork, string, error) {
files, err := libcni.ConfFiles(confDir, []string{".conf", ".conflist", ".json"})
if err != nil {
return nil, "", err
}
networks := make(map[string]*cniNetwork)
defaultNetName := ""
sort.Strings(files)
for _, confFile := range files {
var confList *libcni.NetworkConfigList
if strings.HasSuffix(confFile, ".conflist") {
confList, err = libcni.ConfListFromFile(confFile)
if err != nil {
// do not log ENOENT errors
if !os.IsNotExist(err) {
logrus.Errorf("Error loading CNI config list file %s: %v", confFile, err)
}
continue
}
} else {
conf, err := libcni.ConfFromFile(confFile)
if err != nil {
// do not log ENOENT errors
if !os.IsNotExist(err) {
logrus.Errorf("Error loading CNI config file %s: %v", confFile, err)
}
continue
}
if conf.Network.Type == "" {
logrus.Warningf("Error loading CNI config file %s: no 'type'; perhaps this is a .conflist?", confFile)
continue
}
confList, err = libcni.ConfListFromConf(conf)
if err != nil {
logrus.Errorf("Error converting CNI config file %s to list: %v", confFile, err)
continue
}
}
if len(confList.Plugins) == 0 {
logrus.Infof("CNI config list %s has no networks, skipping", confFile)
continue
}
// Validation on CNI config should be done to pre-check presence
// of plugins which are necessary.
if _, err := cni.ValidateNetworkList(context.TODO(), confList); err != nil {
logrus.Warningf("Error validating CNI config file %s: %v", confFile, err)
continue
}
if confList.Name == "" {
confList.Name = path.Base(confFile)
}
cniNet := &cniNetwork{
name: confList.Name,
filePath: confFile,
config: confList,
}
logrus.Infof("Found CNI network %s (type=%v) at %s", confList.Name, confList.Plugins[0].Network.Type, confFile)
if _, ok := networks[confList.Name]; !ok {
networks[confList.Name] = cniNet
} else {
logrus.Infof("Ignored CNI network %s (type=%v) at %s because already exists", confList.Name, confList.Plugins[0].Network.Type, confFile)
}
if defaultNetName == "" {
defaultNetName = confList.Name
}
}
return networks, defaultNetName, nil
}
const (
loIfname string = "lo"
)
func (plugin *cniNetworkPlugin) syncNetworkConfig() error {
networks, defaultNetName, err := loadNetworks(plugin.confDir, plugin.cniConfig)
if err != nil {
return err
}
plugin.Lock()
defer plugin.Unlock()
// Update defaultNetName if it is changeable
if plugin.defaultNetName.changeable {
plugin.defaultNetName.name = defaultNetName
logrus.Infof("Updated default CNI network name to %s", defaultNetName)
} else {
logrus.Debugf("Default CNI network name %s is unchangeable", plugin.defaultNetName.name)
}
plugin.networks = networks
return nil
}
func (plugin *cniNetworkPlugin) getNetwork(name string) (*cniNetwork, error) {
plugin.RLock()
defer plugin.RUnlock()
net, ok := plugin.networks[name]
if !ok {
return nil, fmt.Errorf("CNI network %q not found", name)
}
return net, nil
}
func (plugin *cniNetworkPlugin) GetDefaultNetworkName() string {
plugin.RLock()
defer plugin.RUnlock()
return plugin.defaultNetName.name
}
func (plugin *cniNetworkPlugin) getDefaultNetwork() *cniNetwork {
defaultNetName := plugin.GetDefaultNetworkName()
if defaultNetName == "" {
return nil
}
network, _ := plugin.getNetwork(defaultNetName)
return network
}
// networksAvailable returns an error if the pod requests no networks and the
// plugin has no default network, and thus the plugin has no idea what network
// to attach the pod to.
func (plugin *cniNetworkPlugin) networksAvailable(podNetwork *PodNetwork) error {
if len(podNetwork.Networks) == 0 && plugin.getDefaultNetwork() == nil {
return fmt.Errorf(errMissingDefaultNetwork, plugin.confDir)
}
return nil
}
func (plugin *cniNetworkPlugin) Name() string {
return CNIPluginName
}
func (plugin *cniNetworkPlugin) loadNetworkFromCache(name string, rt *libcni.RuntimeConf) (*cniNetwork, *libcni.RuntimeConf, error) {
cniNet := &cniNetwork{
name: name,
config: &libcni.NetworkConfigList{
Name: name,
},
}
var confBytes []byte
var err error
confBytes, rt, err = plugin.cniConfig.GetNetworkListCachedConfig(cniNet.config, rt)
if err != nil {
return nil, nil, err
} else if confBytes == nil {
return nil, nil, fmt.Errorf("network %q not found in CNI cache", name)
}
cniNet.config, err = libcni.ConfListFromBytes(confBytes)
if err != nil {
// Might be a plain NetworkConfig
netConf, err := libcni.ConfFromBytes(confBytes)
if err != nil {
return nil, nil, err
}
// Up-convert to a NetworkConfigList
cniNet.config, err = libcni.ConfListFromConf(netConf)
if err != nil {
return nil, nil, err
}
}
return cniNet, rt, nil
}
type forEachNetworkFn func(*cniNetwork, *PodNetwork, *libcni.RuntimeConf) error
func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, fromCache bool, actionFn forEachNetworkFn) error {
networks := podNetwork.Networks
if len(networks) == 0 {
networks = append(networks, NetAttachment{
Name: plugin.GetDefaultNetworkName(),
})
}
allIfNames := make(map[string]bool)
for _, req := range networks {
if req.Ifname != "" {
// Make sure the requested name isn't already assigned
if allIfNames[req.Ifname] {
return fmt.Errorf("network %q requested interface name %q already assigned", req.Name, req.Ifname)
}
allIfNames[req.Ifname] = true
}
}
for _, network := range networks {
ifName := network.Ifname
if ifName == "" {
for i := 0; i < 10000; i++ {
candidate := fmt.Sprintf("eth%d", i)
if !allIfNames[candidate] {
allIfNames[candidate] = true
ifName = candidate
break
}
}
if ifName == "" {
return fmt.Errorf("failed to find free interface name for network %q", network.Name)
}
}
rt, err := buildCNIRuntimeConf(podNetwork, ifName, podNetwork.RuntimeConfig[network.Name])
if err != nil {
logrus.Errorf("error building CNI runtime config: %v", err)
return err
}
var cniNet *cniNetwork
if fromCache {
var newRt *libcni.RuntimeConf
cniNet, newRt, err = plugin.loadNetworkFromCache(network.Name, rt)
if err != nil {
logrus.Errorf("error loading cached network config: %v", err)
logrus.Warningf("falling back to loading from existing plugins on disk")
} else {
// Use the updated RuntimeConf
rt = newRt
}
}
if cniNet == nil {
cniNet, err = plugin.getNetwork(network.Name)
if err != nil {
// try to load the networks again
if err2 := plugin.syncNetworkConfig(); err2 != nil {
logrus.Error(err2)
return err
}
cniNet, err = plugin.getNetwork(network.Name)
if err != nil {
return err
}
}
}
if err := actionFn(cniNet, podNetwork, rt); err != nil {
return err
}
}
return nil
}
func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, error) {
return plugin.SetUpPodWithContext(context.Background(), podNetwork)
}
func (plugin *cniNetworkPlugin) SetUpPodWithContext(ctx context.Context, podNetwork PodNetwork) ([]NetResult, error) {
if err := plugin.networksAvailable(&podNetwork); err != nil {
return nil, err
}
plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork)
// Set up loopback interface
if err := bringUpLoopback(podNetwork.NetNS); err != nil {
logrus.Errorf(err.Error())
return nil, err
}
results := make([]NetResult, 0)
if err := plugin.forEachNetwork(&podNetwork, false, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
fullPodName := buildFullPodName(*podNetwork)
logrus.Infof("Adding pod %s to CNI network %q (type=%v)", fullPodName, network.name, network.config.Plugins[0].Network.Type)
result, err := network.addToNetwork(ctx, rt, plugin.cniConfig)
if err != nil {
return fmt.Errorf("error adding pod %s to CNI network %q: %v", fullPodName, network.name, err)
}
results = append(results, NetResult{
Result: result,
NetAttachment: NetAttachment{
Name: network.name,
Ifname: rt.IfName,
},
})
return nil
}); err != nil {
return nil, err
}
return results, nil
}
func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetAttachment, error) {
cacheDir := libcni.CacheDir
if plugin.cacheDir != "" {
cacheDir = plugin.cacheDir
}
dirPath := filepath.Join(cacheDir, "results")
entries, err := ioutil.ReadDir(dirPath)
if err != nil {
return nil, err
}
fileNames := make([]string, 0, len(entries))
for _, e := range entries {
fileNames = append(fileNames, e.Name())
}
sort.Strings(fileNames)
attachments := []NetAttachment{}
for _, fname := range fileNames {
part := fmt.Sprintf("-%s-", containerID)
pos := strings.Index(fname, part)
if pos <= 0 || pos+len(part) >= len(fname) {
continue
}
cacheFile := filepath.Join(dirPath, fname)
bytes, err := ioutil.ReadFile(cacheFile)
if err != nil {
logrus.Errorf("failed to read CNI cache file %s: %v", cacheFile, err)
continue
}
cachedInfo := struct {
Kind string `json:"kind"`
IfName string `json:"ifName"`
ContainerID string `json:"containerID"`
NetName string `json:"networkName"`
}{}
if err := json.Unmarshal(bytes, &cachedInfo); err != nil {
logrus.Errorf("failed to unmarshal CNI cache file %s: %v", cacheFile, err)
continue
}
if cachedInfo.Kind != libcni.CNICacheV1 {
logrus.Warningf("unknown CNI cache file %s kind %q", cacheFile, cachedInfo.Kind)
continue
}
if cachedInfo.ContainerID != containerID {
continue
}
// Ignore the loopback interface; it's handled separately
if cachedInfo.IfName == loIfname && cachedInfo.NetName == "cni-loopback" {
continue
}
if cachedInfo.IfName == "" || cachedInfo.NetName == "" {
logrus.Warningf("missing CNI cache file %s ifname %q or netname %q", cacheFile, cachedInfo.IfName, cachedInfo.NetName)
continue
}
attachments = append(attachments, NetAttachment{
Name: cachedInfo.NetName,
Ifname: cachedInfo.IfName,
})
}
return attachments, nil
}
// TearDownPod tears down pod networks. Prefers cached pod attachment information
// but falls back to given network attachment information.
func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
return plugin.TearDownPodWithContext(context.Background(), podNetwork)
}
func (plugin *cniNetworkPlugin) TearDownPodWithContext(ctx context.Context, podNetwork PodNetwork) error {
if len(podNetwork.Networks) == 0 {
attachments, err := plugin.getCachedNetworkInfo(podNetwork.ID)
if err == nil && len(attachments) > 0 {
podNetwork.Networks = attachments
}
}
if err := plugin.networksAvailable(&podNetwork); err != nil {
return err
}
plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork)
if err := tearDownLoopback(podNetwork.NetNS); err != nil {
// ignore error
logrus.Warningf("Ignoring error tearing down loopback interface: %v", err)
}
return plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
fullPodName := buildFullPodName(*podNetwork)
logrus.Infof("Deleting pod %s from CNI network %q (type=%v)", fullPodName, network.name, network.config.Plugins[0].Network.Type)
if err := network.deleteFromNetwork(ctx, rt, plugin.cniConfig); err != nil {
return fmt.Errorf("error removing pod %s from CNI network %q: %v", fullPodName, network.name, err)
}
return nil
})
}
// GetPodNetworkStatus returns IP addressing and interface details for all
// networks attached to the pod.
func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]NetResult, error) {
return plugin.GetPodNetworkStatusWithContext(context.Background(), podNetwork)
}
// GetPodNetworkStatusWithContext returns IP addressing and interface details for all
// networks attached to the pod.
func (plugin *cniNetworkPlugin) GetPodNetworkStatusWithContext(ctx context.Context, podNetwork PodNetwork) ([]NetResult, error) {
plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork)
if err := checkLoopback(podNetwork.NetNS); err != nil {
logrus.Errorf(err.Error())
return nil, err
}
results := make([]NetResult, 0)
if err := plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
fullPodName := buildFullPodName(*podNetwork)
logrus.Infof("Checking pod %s for CNI network %s (type=%v)", fullPodName, network.name, network.config.Plugins[0].Network.Type)
result, err := network.checkNetwork(ctx, rt, plugin.cniConfig, plugin.nsManager, podNetwork.NetNS)
if err != nil {
return fmt.Errorf("error checking pod %s for CNI network %q: %v", fullPodName, network.name, err)
}
if result != nil {
results = append(results, NetResult{
Result: result,
NetAttachment: NetAttachment{
Name: network.name,
Ifname: rt.IfName,
},
})
}
return nil
}); err != nil {
return nil, err
}
return results, nil
}
func (network *cniNetwork) addToNetwork(ctx context.Context, rt *libcni.RuntimeConf, cni *libcni.CNIConfig) (cnitypes.Result, error) {
return cni.AddNetworkList(ctx, network.config, rt)
}
func (network *cniNetwork) checkNetwork(ctx context.Context, rt *libcni.RuntimeConf, cni *libcni.CNIConfig, nsManager *nsManager, netns string) (cnitypes.Result, error) {
gtet, err := cniversion.GreaterThanOrEqualTo(network.config.CNIVersion, "0.4.0")
if err != nil {
return nil, err
}
var result cnitypes.Result
// When CNIVersion supports Check, use it. Otherwise fall back on what was done initially.
if gtet {
err = cni.CheckNetworkList(ctx, network.config, rt)
logrus.Infof("Checking CNI network %s (config version=%v)", network.name, network.config.CNIVersion)
if err != nil {
logrus.Errorf("Error checking network: %v", err)
return nil, err
}
}
result, err = cni.GetNetworkListCachedResult(network.config, rt)
if err != nil {
logrus.Errorf("Error getting network list cached result: %v", err)
return nil, err
} else if result != nil {
return result, nil
}
// result doesn't exist, create one
logrus.Infof("Checking CNI network %s (config version=%v) nsManager=%v", network.name, network.config.CNIVersion, nsManager)
var cniInterface *cnicurrent.Interface
ips := []*cnicurrent.IPConfig{}
errs := []error{}
for _, version := range []string{"4", "6"} {
ip, mac, err := getContainerDetails(nsManager, netns, rt.IfName, "-"+version)
if err == nil {
if cniInterface == nil {
cniInterface = &cnicurrent.Interface{
Name: rt.IfName,
Mac: mac.String(),
Sandbox: netns,
}
}
ips = append(ips, &cnicurrent.IPConfig{
Version: version,
Interface: cnicurrent.Int(0),
Address: *ip,
})
} else {
errs = append(errs, err)
}
}
if cniInterface == nil || len(ips) == 0 {
return nil, fmt.Errorf("neither IPv4 nor IPv6 found when retrieving network status: %v", errs)
}
result = &cnicurrent.Result{
CNIVersion: network.config.CNIVersion,
Interfaces: []*cnicurrent.Interface{cniInterface},
IPs: ips,
}
// Result must be the same CNIVersion as the CNI config
converted, err := result.GetAsVersion(network.config.CNIVersion)
if err != nil {
return nil, err
}
return converted, nil
}
func (network *cniNetwork) deleteFromNetwork(ctx context.Context, rt *libcni.RuntimeConf, cni *libcni.CNIConfig) error {
return cni.DelNetworkList(ctx, network.config, rt)
}
func buildCNIRuntimeConf(podNetwork *PodNetwork, ifName string, runtimeConfig RuntimeConfig) (*libcni.RuntimeConf, error) {
logrus.Infof("Got pod network %+v", podNetwork)
rt := &libcni.RuntimeConf{
ContainerID: podNetwork.ID,
NetNS: podNetwork.NetNS,
IfName: ifName,
Args: [][2]string{
{"IgnoreUnknown", "1"},
{"K8S_POD_NAMESPACE", podNetwork.Namespace},
{"K8S_POD_NAME", podNetwork.Name},
{"K8S_POD_INFRA_CONTAINER_ID", podNetwork.ID},
},
CapabilityArgs: map[string]interface{}{},
}
// Propagate existing CNI_ARGS to non-k8s consumers
for _, kvpairs := range strings.Split(os.Getenv("CNI_ARGS"), ";") {
if keyval := strings.SplitN(kvpairs, "=", 2); len(keyval) == 2 {
rt.Args = append(rt.Args, [2]string{keyval[0], keyval[1]})
}
}
// Add requested static IP to CNI_ARGS
ip := runtimeConfig.IP
if ip != "" {
if tstIP := net.ParseIP(ip); tstIP == nil {
return nil, fmt.Errorf("unable to parse IP address %q", ip)
}
rt.Args = append(rt.Args, [2]string{"IP", ip})
}
// Add the requested static MAC to CNI_ARGS
mac := runtimeConfig.MAC
if mac != "" {
_, err := net.ParseMAC(mac)
if err != nil {
return nil, fmt.Errorf("unable to parse MAC address %q: %v", mac, err)
}
rt.Args = append(rt.Args, [2]string{"MAC", mac})
}
// Set PortMappings in Capabilities
if len(runtimeConfig.PortMappings) != 0 {
rt.CapabilityArgs["portMappings"] = runtimeConfig.PortMappings
}
// Set Bandwidth in Capabilities
if runtimeConfig.Bandwidth != nil {
rt.CapabilityArgs["bandwidth"] = map[string]uint64{
"ingressRate": runtimeConfig.Bandwidth.IngressRate,
"ingressBurst": runtimeConfig.Bandwidth.IngressBurst,
"egressRate": runtimeConfig.Bandwidth.EgressRate,
"egressBurst": runtimeConfig.Bandwidth.EgressBurst,
}
}
// Set IpRanges in Capabilities
if len(runtimeConfig.IpRanges) > 0 {
rt.CapabilityArgs["ipRanges"] = runtimeConfig.IpRanges
}
// Set Aliases in Capabilities
if len(podNetwork.Aliases) > 0 {
rt.CapabilityArgs["aliases"] = podNetwork.Aliases
}
return rt, nil
}
func (plugin *cniNetworkPlugin) Status() error {
if plugin.getDefaultNetwork() == nil {
return fmt.Errorf(errMissingDefaultNetwork, plugin.confDir)
}
return nil
}

View File

@ -1,152 +0,0 @@
package ocicni
import (
"context"
"github.com/containernetworking/cni/pkg/types"
)
const (
// DefaultInterfaceName is the string to be used for the interface name inside the net namespace
DefaultInterfaceName = "eth0"
// CNIPluginName is the default name of the plugin
CNIPluginName = "cni"
)
// PortMapping maps to the standard CNI portmapping Capability
// see: https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md
type PortMapping struct {
// HostPort is the port number on the host.
HostPort int32 `json:"hostPort"`
// ContainerPort is the port number inside the sandbox.
ContainerPort int32 `json:"containerPort"`
// Protocol is the protocol of the port mapping.
Protocol string `json:"protocol"`
// HostIP is the host ip to use.
HostIP string `json:"hostIP"`
}
// IpRange maps to the standard CNI ipRanges Capability
// see: https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md
type IpRange struct {
// Subnet is the whole CIDR
Subnet string `json:"subnet"`
// RangeStart is the first available IP in subnet
RangeStart string `json:"rangeStart,omitempty"`
// RangeEnd is the last available IP in subnet
RangeEnd string `json:"rangeEnd,omitempty"`
// Gateway is the gateway of subnet
Gateway string `json:"gateway,omitempty"`
}
// RuntimeConfig is additional configuration for a single CNI network that
// is pod-specific rather than general to the network.
type RuntimeConfig struct {
// IP is a static IP to be specified in the network. Can only be used
// with the hostlocal IP allocator. If left unset, an IP will be
// dynamically allocated.
IP string
// MAC is a static MAC address to be assigned to the network interface.
// If left unset, a MAC will be dynamically allocated.
MAC string
// PortMappings is the port mapping of the sandbox.
PortMappings []PortMapping
// Bandwidth is the bandwidth limiting of the pod
Bandwidth *BandwidthConfig
// IpRanges is the ip range gather which is used for address allocation
IpRanges [][]IpRange
}
// BandwidthConfig maps to the standard CNI bandwidth Capability
// see: https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md
type BandwidthConfig struct {
// IngressRate is a limit for incoming traffic in bps
IngressRate uint64
IngressBurst uint64
// EgressRate is a limit for outgoing traffic in bps
EgressRate uint64
EgressBurst uint64
}
// PodNetwork configures the network of a pod sandbox.
type PodNetwork struct {
// Name is the name of the sandbox.
Name string
// Namespace is the namespace of the sandbox.
Namespace string
// ID is the id of the sandbox container.
ID string
// NetNS is the network namespace path of the sandbox.
NetNS string
// Networks is a list of CNI network names (and optional interface
// names) to attach to the sandbox. Leave this list empty to attach the
// default network to the sandbox
Networks []NetAttachment
// NetworkConfig is configuration specific to a single CNI network.
// It is optional, and can be omitted for some or all specified networks
// without issue.
RuntimeConfig map[string]RuntimeConfig
// Aliases are network-scoped names for resolving a container
// by name. The key value is the network name and the value is
// is a string slice of aliases
Aliases map[string][]string
}
// NetAttachment describes a container network attachment
type NetAttachment struct {
// NetName contains the name of the CNI network to which the container
// should be or is attached
Name string
// Ifname contains the optional interface name of the attachment
Ifname string
}
// NetResult contains the result the network attachment operation
type NetResult struct {
// Result is the CNI Result
Result types.Result
// NetAttachment contains the network and interface names of this
// network attachment
NetAttachment
}
// CNIPlugin is the interface that needs to be implemented by a plugin
type CNIPlugin interface {
// Name returns the plugin's name. This will be used when searching
// for a plugin by name, e.g.
Name() string
// GetDefaultNetworkName returns the name of the plugin's default
// network.
GetDefaultNetworkName() string
// SetUpPod is the method called after the sandbox container of
// the pod has been created but before the other containers of the
// pod are launched.
SetUpPod(network PodNetwork) ([]NetResult, error)
// SetUpPodWithContext is the same as SetUpPod but takes a context
SetUpPodWithContext(ctx context.Context, network PodNetwork) ([]NetResult, error)
// TearDownPod is the method called before a pod's sandbox container will be deleted
TearDownPod(network PodNetwork) error
// TearDownPodWithContext is the same as TearDownPod but takes a context
TearDownPodWithContext(ctx context.Context, network PodNetwork) error
// GetPodNetworkStatus is the method called to obtain the ipv4 or ipv6 addresses of the pod sandbox
GetPodNetworkStatus(network PodNetwork) ([]NetResult, error)
// GetPodNetworkStatusWithContext is the same as GetPodNetworkStatus but takes a context
GetPodNetworkStatusWithContext(ctx context.Context, network PodNetwork) ([]NetResult, error)
// NetworkStatus returns error if the network plugin is in error state
Status() error
// Shutdown terminates all driver operations
Shutdown() error
}

View File

@ -1,10 +0,0 @@
// +build !windows
package ocicni
const (
// DefaultConfDir is the default place to look for CNI Network
DefaultConfDir = "/etc/cni/net.d"
// DefaultBinDir is the default place to look for CNI config files
DefaultBinDir = "/opt/cni/bin"
)

View File

@ -1,10 +0,0 @@
// +build windows
package ocicni
const (
// DefaultConfDir is the default place to look for CNI Network
DefaultConfDir = "C:\\cni\\etc\\net.d"
// DefaultBinDir is the default place to look for cni config files
DefaultBinDir = "C:\\cni\\bin"
)

View File

@ -1,8 +0,0 @@
package ocicni
// newNSManager initializes a new namespace manager, which is a platform dependent struct.
func newNSManager() (*nsManager, error) {
nsm := &nsManager{}
err := nsm.init()
return nsm, err
}

View File

@ -1,150 +0,0 @@
// +build linux
package ocicni
import (
"fmt"
"net"
"os/exec"
"strings"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
)
var defaultNamespaceEnterCommandName = "nsenter"
type nsManager struct {
nsenterPath string
}
func (nsm *nsManager) init() error {
var err error
nsm.nsenterPath, err = exec.LookPath(defaultNamespaceEnterCommandName)
return err
}
func getContainerDetails(nsm *nsManager, netnsPath, interfaceName, addrType string) (*net.IPNet, *net.HardwareAddr, error) {
// Try to retrieve ip inside container network namespace
output, err := exec.Command(nsm.nsenterPath, fmt.Sprintf("--net=%s", netnsPath), "-F", "--",
"ip", "-o", addrType, "addr", "show", "dev", interfaceName, "scope", "global").CombinedOutput()
if err != nil {
return nil, nil, fmt.Errorf("Unexpected command output %s with error: %v", output, err)
}
lines := strings.Split(string(output), "\n")
if len(lines) < 1 {
return nil, nil, fmt.Errorf("Unexpected command output %s", output)
}
fields := strings.Fields(lines[0])
if len(fields) < 4 {
return nil, nil, fmt.Errorf("Unexpected address output %s ", lines[0])
}
ip, ipNet, err := net.ParseCIDR(fields[3])
if err != nil {
return nil, nil, fmt.Errorf("CNI failed to parse ip from output %s due to %v", output, err)
}
if ip.To4() == nil {
ipNet.IP = ip
} else {
ipNet.IP = ip.To4()
}
// Try to retrieve MAC inside container network namespace
output, err = exec.Command(nsm.nsenterPath, fmt.Sprintf("--net=%s", netnsPath), "-F", "--",
"ip", "link", "show", "dev", interfaceName).CombinedOutput()
if err != nil {
return nil, nil, fmt.Errorf("unexpected 'ip link' command output %s with error: %v", output, err)
}
lines = strings.Split(string(output), "\n")
if len(lines) < 2 {
return nil, nil, fmt.Errorf("unexpected 'ip link' command output %s", output)
}
fields = strings.Fields(lines[1])
if len(fields) < 4 {
return nil, nil, fmt.Errorf("unexpected link output %s ", lines[0])
}
mac, err := net.ParseMAC(fields[1])
if err != nil {
return nil, nil, fmt.Errorf("failed to parse MAC from output %s due to %v", output, err)
}
return ipNet, &mac, nil
}
func tearDownLoopback(netns string) error {
return ns.WithNetNSPath(netns, func(_ ns.NetNS) error {
link, err := netlink.LinkByName(loIfname)
if err != nil {
return err // not tested
}
err = netlink.LinkSetDown(link)
if err != nil {
return err // not tested
}
return nil
})
}
func bringUpLoopback(netns string) error {
if err := ns.WithNetNSPath(netns, func(_ ns.NetNS) error {
link, err := netlink.LinkByName(loIfname)
if err == nil {
err = netlink.LinkSetUp(link)
}
if err != nil {
return err
}
v4Addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return err
}
if len(v4Addrs) != 0 {
// sanity check that this is a loopback address
for _, addr := range v4Addrs {
if !addr.IP.IsLoopback() {
return fmt.Errorf("loopback interface found with non-loopback address %q", addr.IP)
}
}
}
v6Addrs, err := netlink.AddrList(link, netlink.FAMILY_V6)
if err != nil {
return err
}
if len(v6Addrs) != 0 {
// sanity check that this is a loopback address
for _, addr := range v6Addrs {
if !addr.IP.IsLoopback() {
return fmt.Errorf("loopback interface found with non-loopback address %q", addr.IP)
}
}
}
return nil
}); err != nil {
return fmt.Errorf("error adding loopback interface: %s", err)
}
return nil
}
func checkLoopback(netns string) error {
// Make sure loopback interface is up
if err := ns.WithNetNSPath(netns, func(_ ns.NetNS) error {
link, err := netlink.LinkByName(loIfname)
if err != nil {
return err
}
if link.Attrs().Flags&net.FlagUp != net.FlagUp {
return fmt.Errorf("loopback interface is down")
}
return nil
}); err != nil {
return fmt.Errorf("error checking loopback interface: %v", err)
}
return nil
}

View File

@ -1,34 +0,0 @@
// +build !linux
package ocicni
import (
"errors"
"net"
)
type nsManager struct {
}
var errUnsupportedPlatform = errors.New("unsupported platform")
func (nsm *nsManager) init() error {
return nil
}
func getContainerDetails(nsm *nsManager, netnsPath, interfaceName, addrType string) (*net.IPNet, *net.HardwareAddr, error) {
return nil, nil, errUnsupportedPlatform
}
func tearDownLoopback(netns string) error {
return errUnsupportedPlatform
}
func bringUpLoopback(netns string) error {
return errUnsupportedPlatform
}
func checkLoopback(netns string) error {
return errUnsupportedPlatform
}

2
vendor/modules.txt vendored
View File

@ -258,8 +258,6 @@ github.com/coreos/stream-metadata-go/fedoracoreos
github.com/coreos/stream-metadata-go/fedoracoreos/internals
github.com/coreos/stream-metadata-go/stream
github.com/coreos/stream-metadata-go/stream/rhcos
# github.com/cri-o/ocicni v0.2.1-0.20210621164014-d0acc7862283
github.com/cri-o/ocicni/pkg/ocicni
# github.com/cyphar/filepath-securejoin v0.2.3
github.com/cyphar/filepath-securejoin
# github.com/davecgh/go-spew v1.1.1