diff --git a/Makefile b/Makefile index a1ad9e50fe..cac83c3072 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ K8S_VERSION=v1.6.6 GOARM=7 # These variables can be overridden by setting an environment variable. -TEST_PACKAGES?=pkg/ip subnet subnet/etcdv2 network backend/hostgw +TEST_PACKAGES?=pkg/ip subnet subnet/etcdv2 network backend TEST_PACKAGES_EXPANDED=$(TEST_PACKAGES:%=github.com/coreos/flannel/%) PACKAGES?=$(TEST_PACKAGES) network PACKAGES_EXPANDED=$(PACKAGES:%=github.com/coreos/flannel/%) diff --git a/backend/common.go b/backend/common.go index f4fb0deceb..a9955e29c5 100644 --- a/backend/common.go +++ b/backend/common.go @@ -15,11 +15,16 @@ package backend import ( + "bytes" "net" + "sync" + "time" "golang.org/x/net/context" "github.com/coreos/flannel/subnet" + log "github.com/golang/glog" + "github.com/vishvananda/netlink" ) type ExternalInterface struct { @@ -61,3 +66,176 @@ func (n *SimpleNetwork) MTU() int { func (_ *SimpleNetwork) Run(ctx context.Context) { <-ctx.Done() } + +const ( + routeCheckRetries = 10 +) + +type RouteNetwork struct { + SimpleNetwork + BackendType string + routes []netlink.Route + SM subnet.Manager + GetRoute func(lease *subnet.Lease) *netlink.Route + Mtu int + LinkIndex int +} + +func (n *RouteNetwork) MTU() int { + return n.Mtu +} + +func (n *RouteNetwork) Run(ctx context.Context) { + wg := sync.WaitGroup{} + + log.Info("Watching for new subnet leases") + evts := make(chan []subnet.Event) + wg.Add(1) + go func() { + subnet.WatchLeases(ctx, n.SM, n.SubnetLease, evts) + wg.Done() + }() + + n.routes = make([]netlink.Route, 0, 10) + wg.Add(1) + go func() { + n.routeCheck(ctx) + wg.Done() + }() + + defer wg.Wait() + + for { + select { + case evtBatch := <-evts: + n.handleSubnetEvents(evtBatch) + + case <-ctx.Done(): + return + } + } +} + +func (n *RouteNetwork) handleSubnetEvents(batch []subnet.Event) { + for _, evt := range batch { + switch evt.Type { + case subnet.EventAdded: + log.Infof("Subnet added: %v via %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP) + + if evt.Lease.Attrs.BackendType != n.BackendType { + log.Warningf("Ignoring non-%v subnet: type=%v", n.BackendType, evt.Lease.Attrs.BackendType) + continue + } + route := n.GetRoute(&evt.Lease) + + n.addToRouteList(*route) + // Check if route exists before attempting to add it + routeList, err := netlink.RouteListFiltered(netlink.FAMILY_V4, &netlink.Route{Dst: route.Dst}, netlink.RT_FILTER_DST) + if err != nil { + log.Warningf("Unable to list routes: %v", err) + } + if len(routeList) > 0 && !routeEqual(routeList[0], *route) { + // Same Dst different Gw or different link index. Remove it, correct route will be added below. + log.Warningf("Replacing existing route to %v via %v dev index %d with %v via %v dev index %d.", evt.Lease.Subnet, routeList[0].Gw, routeList[0].LinkIndex, evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, route.LinkIndex) + if err := netlink.RouteDel(&routeList[0]); err != nil { + log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err) + continue + } + n.removeFromRouteList(routeList[0]) + } + if len(routeList) > 0 && routeEqual(routeList[0], *route) { + // Same Dst and same Gw, keep it and do not attempt to add it. + log.Infof("Route to %v via %v dev index %d already exists, skipping.", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, routeList[0].LinkIndex) + } else if err := netlink.RouteAdd(route); err != nil { + log.Errorf("Error adding route to %v via %v dev index %d: %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, route.LinkIndex, err) + continue + } + + case subnet.EventRemoved: + log.Info("Subnet removed: ", evt.Lease.Subnet) + + if evt.Lease.Attrs.BackendType != n.BackendType { + log.Warningf("Ignoring non-%v subnet: type=%v", n.BackendType, evt.Lease.Attrs.BackendType) + continue + } + + route := n.GetRoute(&evt.Lease) + // Always remove the route from the route list. + n.removeFromRouteList(*route) + + if err := netlink.RouteDel(route); err != nil { + log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err) + continue + } + + default: + log.Error("Internal error: unknown event type: ", int(evt.Type)) + } + } +} + +func (n *RouteNetwork) addToRouteList(route netlink.Route) { + for _, r := range n.routes { + if routeEqual(r, route) { + return + } + } + n.routes = append(n.routes, route) +} + +func (n *RouteNetwork) removeFromRouteList(route netlink.Route) { + for index, r := range n.routes { + if routeEqual(r, route) { + n.routes = append(n.routes[:index], n.routes[index+1:]...) + return + } + } +} + +func (n *RouteNetwork) routeCheck(ctx context.Context) { + for { + select { + case <-ctx.Done(): + return + case <-time.After(routeCheckRetries * time.Second): + n.checkSubnetExistInRoutes() + } + } +} + +func (n *RouteNetwork) checkSubnetExistInRoutes() { + routeList, err := netlink.RouteList(nil, netlink.FAMILY_V4) + if err == nil { + for _, route := range n.routes { + exist := false + for _, r := range routeList { + if r.Dst == nil { + continue + } + if routeEqual(r, route) { + exist = true + break + } + } + if !exist { + if err := netlink.RouteAdd(&route); err != nil { + if nerr, ok := err.(net.Error); !ok { + log.Errorf("Error recovering route to %v: %v, %v", route.Dst, route.Gw, nerr) + } + continue + } else { + log.Infof("Route recovered %v : %v", route.Dst, route.Gw) + } + } + } + } else { + log.Errorf("Error fetching route list. Will automatically retry: %v", err) + } +} + +func routeEqual(x, y netlink.Route) bool { + if x.Dst.IP.Equal(y.Dst.IP) && x.Gw.Equal(y.Gw) && bytes.Equal(x.Dst.Mask, y.Dst.Mask) && x.LinkIndex == y.LinkIndex { + return true + } + return false +} diff --git a/backend/hostgw/hostgw_network_test.go b/backend/common_test.go similarity index 70% rename from backend/hostgw/hostgw_network_test.go rename to backend/common_test.go index 47178ec2ff..c493b8a68e 100644 --- a/backend/hostgw/hostgw_network_test.go +++ b/backend/common_test.go @@ -1,4 +1,4 @@ -// Copyright 2015 flannel authors +// Copyright 2017 flannel authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,13 +13,12 @@ // limitations under the License. // +build !windows -package hostgw +package backend import ( "net" "testing" - "github.com/coreos/flannel/backend" "github.com/coreos/flannel/pkg/ip" "github.com/coreos/flannel/pkg/ns" "github.com/coreos/flannel/subnet" @@ -40,26 +39,37 @@ func TestRouteCache(t *testing.T) { if err := netlink.LinkSetUp(lo); err != nil { t.Fatal(err) } - nw := network{extIface: &backend.ExternalInterface{Iface: &net.Interface{Index: lo.Attrs().Index}}} + nw := RouteNetwork{ + SimpleNetwork: SimpleNetwork{ + ExtIface: &ExternalInterface{Iface: &net.Interface{Index: lo.Attrs().Index}}, + }, + } + nw.GetRoute = func(lease *subnet.Lease) *netlink.Route { + return &netlink.Route{ + Dst: lease.Subnet.ToIPNet(), + Gw: lease.Attrs.PublicIP.ToIP(), + LinkIndex: nw.LinkIndex, + } + } gw1, gw2 := ip.FromIP(net.ParseIP("127.0.0.1")), ip.FromIP(net.ParseIP("127.0.0.2")) subnet1 := ip.IP4Net{IP: ip.FromIP(net.ParseIP("192.168.0.0")), PrefixLen: 24} nw.handleSubnetEvents([]subnet.Event{ {Type: subnet.EventAdded, Lease: subnet.Lease{Subnet: subnet1, Attrs: subnet.LeaseAttrs{PublicIP: gw1, BackendType: "host-gw"}}}, }) - if len(nw.rl) != 1 { - t.Fatal(nw.rl) + if len(nw.routes) != 1 { + t.Fatal(nw.routes) } - if !routeEqual(nw.rl[0], netlink.Route{Dst: subnet1.ToIPNet(), Gw: gw1.ToIP()}) { - t.Fatal(nw.rl[0]) + if !routeEqual(nw.routes[0], netlink.Route{Dst: subnet1.ToIPNet(), Gw: gw1.ToIP()}) { + t.Fatal(nw.routes[0]) } // change gateway of previous route nw.handleSubnetEvents([]subnet.Event{ {Type: subnet.EventAdded, Lease: subnet.Lease{ Subnet: subnet1, Attrs: subnet.LeaseAttrs{PublicIP: gw2, BackendType: "host-gw"}}}}) - if len(nw.rl) != 1 { - t.Fatal(nw.rl) + if len(nw.routes) != 1 { + t.Fatal(nw.routes) } - if !routeEqual(nw.rl[0], netlink.Route{Dst: subnet1.ToIPNet(), Gw: gw2.ToIP()}) { - t.Fatal(nw.rl[0]) + if !routeEqual(nw.routes[0], netlink.Route{Dst: subnet1.ToIPNet(), Gw: gw2.ToIP()}) { + t.Fatal(nw.routes[0]) } } diff --git a/backend/hostgw/hostgw.go b/backend/hostgw/hostgw.go index 3ba5e60cbe..ac3f694f6e 100644 --- a/backend/hostgw/hostgw.go +++ b/backend/hostgw/hostgw.go @@ -21,6 +21,7 @@ import ( "github.com/coreos/flannel/backend" "github.com/coreos/flannel/pkg/ip" "github.com/coreos/flannel/subnet" + "github.com/vishvananda/netlink" "golang.org/x/net/context" ) @@ -28,14 +29,9 @@ func init() { backend.Register("host-gw", New) } -const ( - routeCheckRetries = 10 -) - type HostgwBackend struct { sm subnet.Manager extIface *backend.ExternalInterface - networks map[string]*network } func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backend, error) { @@ -46,16 +42,26 @@ func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backen be := &HostgwBackend{ sm: sm, extIface: extIface, - networks: make(map[string]*network), } - return be, nil } func (be *HostgwBackend) RegisterNetwork(ctx context.Context, config *subnet.Config) (backend.Network, error) { - n := &network{ - extIface: be.extIface, - sm: be.sm, + n := &backend.RouteNetwork{ + SimpleNetwork: backend.SimpleNetwork{ + ExtIface: be.extIface, + }, + SM: be.sm, + BackendType: "host-gw", + Mtu: be.extIface.Iface.MTU, + LinkIndex: be.extIface.Iface.Index, + } + n.GetRoute = func(lease *subnet.Lease) *netlink.Route { + return &netlink.Route{ + Dst: lease.Subnet.ToIPNet(), + Gw: lease.Attrs.PublicIP.ToIP(), + LinkIndex: n.LinkIndex, + } } attrs := subnet.LeaseAttrs{ @@ -66,7 +72,7 @@ func (be *HostgwBackend) RegisterNetwork(ctx context.Context, config *subnet.Con l, err := be.sm.AcquireLease(ctx, &attrs) switch err { case nil: - n.lease = l + n.SubnetLease = l case context.Canceled, context.DeadlineExceeded: return nil, err diff --git a/backend/hostgw/hostgw_network.go b/backend/hostgw/hostgw_network.go deleted file mode 100644 index 3d913a2c81..0000000000 --- a/backend/hostgw/hostgw_network.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2015 flannel authors -// -// 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. -// +build !windows - -package hostgw - -import ( - "bytes" - "net" - "sync" - "time" - - log "github.com/golang/glog" - "github.com/vishvananda/netlink" - "golang.org/x/net/context" - - "github.com/coreos/flannel/backend" - "github.com/coreos/flannel/subnet" -) - -type network struct { - name string - extIface *backend.ExternalInterface - rl []netlink.Route - lease *subnet.Lease - sm subnet.Manager -} - -func (n *network) Lease() *subnet.Lease { - return n.lease -} - -func (n *network) MTU() int { - return n.extIface.Iface.MTU -} - -func (n *network) LinkIndex() int { - return n.extIface.Iface.Index -} - -func (n *network) Run(ctx context.Context) { - wg := sync.WaitGroup{} - - log.Info("Watching for new subnet leases") - evts := make(chan []subnet.Event) - wg.Add(1) - go func() { - subnet.WatchLeases(ctx, n.sm, n.lease, evts) - wg.Done() - }() - - // Store a list of routes, initialized to capacity of 10. - n.rl = make([]netlink.Route, 0, 10) - wg.Add(1) - - // Start a goroutine which periodically checks that the right routes are created - go func() { - n.routeCheck(ctx) - wg.Done() - }() - - defer wg.Wait() - - for { - select { - case evtBatch := <-evts: - n.handleSubnetEvents(evtBatch) - - case <-ctx.Done(): - return - } - } -} - -func (n *network) handleSubnetEvents(batch []subnet.Event) { - for _, evt := range batch { - switch evt.Type { - case subnet.EventAdded: - log.Infof("Subnet added: %v via %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP) - - if evt.Lease.Attrs.BackendType != "host-gw" { - log.Warningf("Ignoring non-host-gw subnet: type=%v", evt.Lease.Attrs.BackendType) - continue - } - - route := netlink.Route{ - Dst: evt.Lease.Subnet.ToIPNet(), - Gw: evt.Lease.Attrs.PublicIP.ToIP(), - LinkIndex: n.LinkIndex(), - } - - // Always add the route to the route list. - n.addToRouteList(route) - - // Check if route exists before attempting to add it - routeList, err := netlink.RouteListFiltered(netlink.FAMILY_V4, &netlink.Route{ - Dst: route.Dst, - }, netlink.RT_FILTER_DST) - if err != nil { - log.Warningf("Unable to list routes: %v", err) - } - // Check match on Dst for match on Gw - if len(routeList) > 0 && !routeList[0].Gw.Equal(route.Gw) { - // Same Dst different Gw. Remove it, correct route will be added below. - log.Warningf("Replacing existing route to %v via %v with %v via %v.", evt.Lease.Subnet, routeList[0].Gw, evt.Lease.Subnet, evt.Lease.Attrs.PublicIP) - if err := netlink.RouteDel(&routeList[0]); err != nil { - log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err) - continue - } - n.removeFromRouteList(routeList[0]) - } - if len(routeList) > 0 && routeList[0].Gw.Equal(route.Gw) { - // Same Dst and same Gw, keep it and do not attempt to add it. - log.Infof("Route to %v via %v already exists, skipping.", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP) - } else if err := netlink.RouteAdd(&route); err != nil { - log.Errorf("Error adding route to %v via %v: %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, err) - continue - } - - case subnet.EventRemoved: - log.Info("Subnet removed: ", evt.Lease.Subnet) - - if evt.Lease.Attrs.BackendType != "host-gw" { - log.Warningf("Ignoring non-host-gw subnet: type=%v", evt.Lease.Attrs.BackendType) - continue - } - - route := netlink.Route{ - Dst: evt.Lease.Subnet.ToIPNet(), - Gw: evt.Lease.Attrs.PublicIP.ToIP(), - LinkIndex: n.LinkIndex(), - } - - // Always remove the route from the route list. - n.removeFromRouteList(route) - - if err := netlink.RouteDel(&route); err != nil { - log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err) - continue - } - - default: - log.Error("Internal error: unknown event type: ", int(evt.Type)) - } - } -} - -func (n *network) addToRouteList(route netlink.Route) { - for _, r := range n.rl { - if routeEqual(r, route) { - return - } - } - n.rl = append(n.rl, route) -} - -func (n *network) removeFromRouteList(route netlink.Route) { - for index, r := range n.rl { - if routeEqual(r, route) { - n.rl = append(n.rl[:index], n.rl[index+1:]...) - return - } - } -} - -func (n *network) routeCheck(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case <-time.After(routeCheckRetries * time.Second): - n.checkSubnetExistInRoutes() - } - } -} - -func (n *network) checkSubnetExistInRoutes() { - routeList, err := netlink.RouteList(nil, netlink.FAMILY_V4) - if err == nil { - for _, route := range n.rl { - exist := false - for _, r := range routeList { - if r.Dst == nil { - continue - } - if routeEqual(r, route) { - exist = true - break - } - } - if !exist { - if err := netlink.RouteAdd(&route); err != nil { - if nerr, ok := err.(net.Error); !ok { - log.Errorf("Error recovering route to %v: %v, %v", route.Dst, route.Gw, nerr) - } - continue - } else { - log.Infof("Route recovered %v : %v", route.Dst, route.Gw) - } - } - } - } else { - log.Errorf("Error fetching route list. Will automatically retry: %v", err) - } -} - -func routeEqual(x, y netlink.Route) bool { - if x.Dst.IP.Equal(y.Dst.IP) && x.Gw.Equal(y.Gw) && bytes.Equal(x.Dst.Mask, y.Dst.Mask) { - return true - } - return false -} diff --git a/backend/ipip/ipip.go b/backend/ipip/ipip.go index 589be3d9a8..1cdf6786a3 100644 --- a/backend/ipip/ipip.go +++ b/backend/ipip/ipip.go @@ -60,12 +60,12 @@ func (be *IPIPBackend) RegisterNetwork(ctx context.Context, config *subnet.Confi } glog.Infof("IPIP config: DirectRouting=%v", cfg.DirectRouting) - n := &network{ + n := &backend.RouteNetwork{ SimpleNetwork: backend.SimpleNetwork{ ExtIface: be.extIface, }, - sm: be.sm, - backendType: backendType, + SM: be.sm, + BackendType: backendType, } attrs := &subnet.LeaseAttrs{ @@ -82,17 +82,36 @@ func (be *IPIPBackend) RegisterNetwork(ctx context.Context, config *subnet.Confi default: return nil, fmt.Errorf("failed to acquire lease: %v", err) } - dev, err := be.configureIPIPDevice(n.SubnetLease) + link, err := be.configureIPIPDevice(n.SubnetLease) if err != nil { return nil, err } - dev.directRouting = cfg.DirectRouting - n.dev = dev + n.Mtu = link.MTU + n.LinkIndex = link.Index + n.GetRoute = func(lease *subnet.Lease) *netlink.Route { + route := netlink.Route{ + Dst: lease.Subnet.ToIPNet(), + Gw: lease.Attrs.PublicIP.ToIP(), + LinkIndex: n.LinkIndex, + Flags: int(netlink.FLAG_ONLINK), + } + if cfg.DirectRouting { + dr, err := ip.DirectRouting(lease.Attrs.PublicIP.ToIP()) + if err != nil { + glog.Error(err) + } + if dr { + glog.V(2).Infof("configure route to %v via direct routing", lease.Attrs.PublicIP.String()) + route.LinkIndex = n.ExtIface.Iface.Index + } + } + return &route + } return n, nil } -func (be *IPIPBackend) configureIPIPDevice(lease *subnet.Lease) (*tunnelDev, error) { +func (be *IPIPBackend) configureIPIPDevice(lease *subnet.Lease) (*netlink.Iptun, error) { // When modprobe ipip module, a tunl0 ipip device is created automatically per network namespace by ipip kernel module. // It is the namespace default IPIP device with attributes local=any and remote=any. // When receiving IPIP protocol packets, kernel will forward them to tunl0 as a fallback device @@ -162,10 +181,5 @@ func (be *IPIPBackend) configureIPIPDevice(lease *subnet.Lease) (*tunnelDev, err if err := netlink.LinkSetUp(link); err != nil { return nil, fmt.Errorf("failed to set %v UP: %v", tunnelName, err) } - return &tunnelDev{iptun: link}, nil -} - -type tunnelDev struct { - iptun *netlink.Iptun - directRouting bool + return link, nil } diff --git a/backend/ipip/ipip_network.go b/backend/ipip/ipip_network.go deleted file mode 100644 index 1b4469db52..0000000000 --- a/backend/ipip/ipip_network.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2017 flannel authors -// -// 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 ipip - -import ( - "bytes" - "net" - "sync" - "time" - - "github.com/coreos/flannel/backend" - "github.com/coreos/flannel/pkg/ip" - "github.com/coreos/flannel/subnet" - log "github.com/golang/glog" - "github.com/vishvananda/netlink" - "golang.org/x/net/context" -) - -const ( - routeCheckRetries = 10 -) - -type network struct { - backend.SimpleNetwork - backendType string - routes []netlink.Route - sm subnet.Manager - dev *tunnelDev -} - -func (n *network) MTU() int { - return n.dev.iptun.Attrs().MTU -} - -func (n *network) Run(ctx context.Context) { - wg := sync.WaitGroup{} - - log.Info("Watching for new subnet leases") - evts := make(chan []subnet.Event) - wg.Add(1) - go func() { - subnet.WatchLeases(ctx, n.sm, n.SubnetLease, evts) - wg.Done() - }() - - n.routes = make([]netlink.Route, 0, 10) - wg.Add(1) - go func() { - n.routeCheck(ctx) - wg.Done() - }() - - defer wg.Wait() - - for { - select { - case evtBatch := <-evts: - n.handleSubnetEvents(evtBatch) - - case <-ctx.Done(): - return - } - } -} - -func (n *network) handleSubnetEvents(batch []subnet.Event) { - for _, evt := range batch { - switch evt.Type { - case subnet.EventAdded: - log.Infof("Subnet added: %v via %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP) - - if evt.Lease.Attrs.BackendType != n.backendType { - log.Warningf("Ignoring non-%v subnet: type=%v", n.backendType, evt.Lease.Attrs.BackendType) - continue - } - route := n.getRoute(&evt.Lease) - - n.addToRouteList(*route) - // Check if route exists before attempting to add it - routeList, err := netlink.RouteListFiltered(netlink.FAMILY_V4, &netlink.Route{Dst: route.Dst}, netlink.RT_FILTER_DST) - if err != nil { - log.Warningf("Unable to list routes: %v", err) - } - if len(routeList) > 0 && (!routeList[0].Gw.Equal(route.Gw) || routeList[0].LinkIndex != route.LinkIndex) { - // Same Dst different Gw or different link index. Remove it, correct route will be added below. - log.Warningf("Replacing existing route to %v via %v dev index %d with %v via %v dev index %d.", evt.Lease.Subnet, routeList[0].Gw, routeList[0].LinkIndex, evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, route.LinkIndex) - if err := netlink.RouteDel(&routeList[0]); err != nil { - log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err) - continue - } - n.removeFromRouteList(routeList[0]) - } - if len(routeList) > 0 && routeList[0].Gw.Equal(route.Gw) && routeList[0].LinkIndex == route.LinkIndex { - // Same Dst and same Gw, keep it and do not attempt to add it. - log.Infof("Route to %v via %v dev index %d already exists, skipping.", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, routeList[0].LinkIndex) - } else if err := netlink.RouteAdd(route); err != nil { - log.Errorf("Error adding route to %v via %v dev index %d: %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, route.LinkIndex, err) - continue - } - - case subnet.EventRemoved: - log.Info("Subnet removed: ", evt.Lease.Subnet) - - if evt.Lease.Attrs.BackendType != n.backendType { - log.Warningf("Ignoring non-%v subnet: type=%v", n.backendType, evt.Lease.Attrs.BackendType) - continue - } - - route := n.getRoute(&evt.Lease) - if err := netlink.RouteDel(route); err != nil { - log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err) - continue - } - n.removeFromRouteList(*route) - - default: - log.Error("Internal error: unknown event type: ", int(evt.Type)) - } - } -} - -func (n *network) addToRouteList(route netlink.Route) { - for _, r := range n.routes { - if routeEqual(r, route) { - return - } - } - n.routes = append(n.routes, route) -} - -func (n *network) removeFromRouteList(route netlink.Route) { - for index, r := range n.routes { - if routeEqual(r, route) { - n.routes = append(n.routes[:index], n.routes[index+1:]...) - return - } - } -} - -func (n *network) routeCheck(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case <-time.After(routeCheckRetries * time.Second): - n.checkSubnetExistInRoutes() - } - } -} - -func (n *network) checkSubnetExistInRoutes() { - routeList, err := netlink.RouteList(nil, netlink.FAMILY_V4) - if err == nil { - for _, route := range n.routes { - exist := false - for _, r := range routeList { - if r.Dst == nil { - continue - } - if routeEqual(r, route) { - exist = true - break - } - } - if !exist { - if err := netlink.RouteAdd(&route); err != nil { - if nerr, ok := err.(net.Error); !ok { - log.Errorf("Error recovering route to %v: %v, %v", route.Dst, route.Gw, nerr) - } - continue - } else { - log.Infof("Route recovered %v : %v", route.Dst, route.Gw) - } - } - } - } -} - -func routeEqual(x, y netlink.Route) bool { - if x.Dst.IP.Equal(y.Dst.IP) && x.Gw.Equal(y.Gw) && bytes.Equal(x.Dst.Mask, y.Dst.Mask) && x.LinkIndex == y.LinkIndex { - return true - } - return false -} - -func (n *network) getRoute(lease *subnet.Lease) *netlink.Route { - route := netlink.Route{ - Dst: lease.Subnet.ToIPNet(), - Gw: lease.Attrs.PublicIP.ToIP(), - LinkIndex: n.dev.iptun.Attrs().Index, - Flags: int(netlink.FLAG_ONLINK), - } - if n.dev.directRouting { - dr, err := ip.DirectRouting(lease.Attrs.PublicIP.ToIP()) - if err != nil { - log.Error(err) - } - if dr { - log.V(2).Infof("configure route to %v via direct routing", lease.Attrs.PublicIP.String()) - route.LinkIndex = n.ExtIface.Iface.Index - } - } - return &route -} diff --git a/backend/hostgw/hostgw_network_windows.go b/backend/ipip/ipip_windows.go similarity index 52% rename from backend/hostgw/hostgw_network_windows.go rename to backend/ipip/ipip_windows.go index 5ff3e18535..576c85ea19 100644 --- a/backend/hostgw/hostgw_network_windows.go +++ b/backend/ipip/ipip_windows.go @@ -1,4 +1,4 @@ -// Copyright 2015 flannel authors +// Copyright 2017 flannel authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,34 +13,12 @@ // limitations under the License. // +build windows -package hostgw +package ipip import ( - "golang.org/x/net/context" - - "github.com/coreos/flannel/backend" - "github.com/coreos/flannel/subnet" - - netroute "github.com/rakelkar/gonetsh/netroute" + log "github.com/golang/glog" ) -type network struct { - name string - extIface *backend.ExternalInterface - linkIndex int - rl []netroute.Route - lease *subnet.Lease - sm subnet.Manager -} - -func (n *network) Lease() *subnet.Lease { - return n.lease -} - -func (n *network) MTU() int { - return n.extIface.Iface.MTU -} - -func (n *network) Run(ctx context.Context) { - +func init() { + log.Infof("ipip is not supported on this platform") }