cmd/kube-egress-cni-ipam/main.go (106 lines of code) (raw):
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
package main
import (
"errors"
"net"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
type100 "github.com/containernetworking/cni/pkg/types/100"
"github.com/containernetworking/cni/pkg/version"
"github.com/containernetworking/plugins/pkg/ns"
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
"github.com/vishvananda/netlink"
"golang.org/x/sys/unix"
"github.com/Azure/kube-egress-gateway/pkg/cni/conf"
"github.com/Azure/kube-egress-gateway/pkg/consts"
"github.com/Azure/kube-egress-gateway/pkg/logger"
)
func main() {
skel.PluginMainFuncs(skel.CNIFuncs{Add: cmdAdd, Check: cmdCheck, Del: cmdDel}, version.All, bv.BuildString(consts.KubeEgressIPAMCNIName))
}
func cmdAdd(args *skel.CmdArgs) error {
log := logger.GetLogger()
// get cni config
config, err := conf.ParseCNIConfig(args.StdinData)
if err != nil {
return err
}
// get k8s metadata
k8sInfo, err := conf.LoadK8sInfo(args.Args)
if err != nil {
return err
}
log.V(5).Info("ADD - IPAM configuration successfully read: %+v", *k8sInfo)
// allocate ip
if config == nil || config.IPAM.Type == "" {
return errors.New("ipam should not be empty")
}
podNetNS, err := ns.GetNS(args.Netns)
if err != nil {
return err
}
defer podNetNS.Close()
var v4Address, v6Address net.IPNet
var ipv4AddrFound, ipv6AddrFound bool
var extraRoutes []*types.Route
err = podNetNS.Do(func(netNS ns.NetNS) error {
eth0Link, err := netlink.LinkByName("eth0")
if err != nil {
return err
}
addrList, err := netlink.AddrList(eth0Link, netlink.FAMILY_V6)
if err != nil {
return err
}
for _, item := range addrList {
if item.Scope == unix.RT_SCOPE_LINK {
v6Address = *item.IPNet
ipv6AddrFound = true
}
}
addrList, err = netlink.AddrList(eth0Link, netlink.FAMILY_V4)
if err != nil {
return err
}
for _, item := range addrList {
if item.Scope == unix.RT_SCOPE_UNIVERSE {
v4Address = *item.IPNet
ipv4AddrFound = true
}
}
return nil
})
if err != nil {
return err
}
if !ipv4AddrFound {
return errors.New("there is no enough ipv4 addr allocated for this pod")
}
if !ipv6AddrFound {
return errors.New("there is no enough ipv6 addr allocated for this pod")
}
result := &type100.Result{
CNIVersion: type100.ImplementedSpecVersion,
IPs: []*type100.IPConfig{
{
Address: v6Address,
Gateway: net.ParseIP(consts.GatewayIP),
},
{
Address: v4Address,
},
},
Routes: extraRoutes,
}
// outputCmdArgs(args)
return types.PrintResult(result, config.CNIVersion)
}
func cmdDel(args *skel.CmdArgs) error {
// get cni config
config, err := conf.ParseCNIConfig(args.StdinData)
if err != nil {
return err
}
return types.PrintResult(&type100.Result{}, config.CNIVersion)
}
func cmdCheck(args *skel.CmdArgs) error {
// get cni config
config, err := conf.ParseCNIConfig(args.StdinData)
if err != nil {
return err
}
return types.PrintResult(&type100.Result{}, config.CNIVersion)
}