Set a default route via bridge if config doesn't specify any
This commit is contained in:
1 parent
42ff61f97c
commit
ac4e87418a
1 file changed
+85
-6
+85
-6
@@ -4,6 +4,8 @@ import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/appc/cni/pkg/ipam"
|
||||
"github.com/appc/cni/pkg/skel"
|
||||
@@ -15,6 +17,11 @@ import (
|
||||
ipamplugin "github.com/weaveworks/weave/plugin/ipam"
|
||||
)
|
||||
|
||||
var (
|
||||
zeroNetwork = net.IPNet{IP: net.IPv4zero, Mask: net.IPv4Mask(0, 0, 0, 0)}
|
||||
mask32 = net.IPv4Mask(0xff, 0xff, 0xff, 0xff)
|
||||
)
|
||||
|
||||
type CNIPlugin struct {
|
||||
weave *weaveapi.Client
|
||||
}
|
||||
@@ -97,15 +104,17 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
|
||||
return cleanup(errorf("IPAM plugin failed to allocate IP address"))
|
||||
}
|
||||
|
||||
err = common.WithNetNS(ns, func() error {
|
||||
guest, err := netlink.LinkByName(local.PeerName)
|
||||
// If config says nothing about routes or gateway, default one will be via the bridge
|
||||
if result.IP4.Routes == nil && result.IP4.Gateway == nil {
|
||||
bridgeIP, err := findBridgeIP(conf.BrName, result.IP4.IP)
|
||||
if err != nil {
|
||||
return cleanup(err)
|
||||
}
|
||||
if err = netlink.LinkSetName(guest, args.IfName); err != nil {
|
||||
return err
|
||||
}
|
||||
return ipam.ConfigureIface(args.IfName, result)
|
||||
result.IP4.Gateway = bridgeIP
|
||||
}
|
||||
|
||||
err = common.WithNetNS(ns, func() error {
|
||||
return setupGuestIP4(local.PeerName, args.IfName, result.IP4.IP, result.IP4.Gateway, result.IP4.Routes)
|
||||
})
|
||||
if err != nil {
|
||||
return cleanup(errorf("error setting up interface: %s", err))
|
||||
@@ -115,6 +124,76 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
|
||||
return result.Print()
|
||||
}
|
||||
|
||||
func setupGuestIP4(origName, name string, ipnet net.IPNet, gw net.IP, routes []types.Route) error {
|
||||
guest, err := netlink.LinkByName(origName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = netlink.LinkSetName(guest, name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = netlink.LinkSetUp(guest); err != nil {
|
||||
return err
|
||||
}
|
||||
if routes == nil { // If config says nothing about routes, add a default one
|
||||
if !ipnet.Contains(gw) {
|
||||
// The bridge IP is not on the same subnet; add a specific route to it
|
||||
gw32 := &net.IPNet{IP: gw, Mask: mask32}
|
||||
if err = addRoute(guest, netlink.SCOPE_LINK, gw32, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
routes = []types.Route{{Dst: zeroNetwork}}
|
||||
}
|
||||
if err = netlink.AddrAdd(guest, &netlink.Addr{IPNet: &ipnet}); err != nil {
|
||||
return fmt.Errorf("failed to add IP address to %q: %v", name, err)
|
||||
}
|
||||
for _, r := range routes {
|
||||
if r.GW != nil {
|
||||
err = addRoute(guest, netlink.SCOPE_UNIVERSE, &r.Dst, r.GW)
|
||||
} else {
|
||||
err = addRoute(guest, netlink.SCOPE_UNIVERSE, &r.Dst, gw)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to add route '%v via %v dev %v': %v", r.Dst, gw, name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRoute(link netlink.Link, scope netlink.Scope, dst *net.IPNet, gw net.IP) error {
|
||||
err := netlink.RouteAdd(&netlink.Route{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Scope: scope,
|
||||
Dst: dst,
|
||||
Gw: gw,
|
||||
})
|
||||
if os.IsExist(err) { // squash duplicate route errors
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func findBridgeIP(bridgeName string, subnet net.IPNet) (net.IP, error) {
|
||||
netdevs, err := common.GetBridgeNetDev(bridgeName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err)
|
||||
}
|
||||
if len(netdevs) == 0 {
|
||||
return nil, fmt.Errorf("Could not find %q bridge", bridgeName)
|
||||
}
|
||||
if len(netdevs[0].CIDRs) == 0 {
|
||||
return nil, fmt.Errorf("Bridge %q has no IP addresses", bridgeName)
|
||||
}
|
||||
for _, cidr := range netdevs[0].CIDRs {
|
||||
if subnet.Contains(cidr.IP) {
|
||||
return cidr.IP, nil
|
||||
}
|
||||
}
|
||||
// None in the required subnet; just return the first one
|
||||
return netdevs[0].CIDRs[0].IP, nil
|
||||
}
|
||||
|
||||
func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
|
||||
conf, err := loadNetConf(args.StdinData)
|
||||
if err != nil {
|
||||
|
||||
Reference in new issue
Block a user