From a50e885121d18a64638f7714148d96a5381b0d58 Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Thu, 13 Jul 2017 16:50:56 -0700 Subject: [PATCH] When the gc_thresh3 value is reached kenel might remove existing neighbor entries. On an l3 miss try to reprogram the neighbor entry if the peer is valid. Its a best effort attempt because if the arp table is still at gc_thresh3 value, addition will fail. Signed-off-by: Santhosh Manohar --- libnetwork/drivers/overlay/ov_network.go | 65 ++++++++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/libnetwork/drivers/overlay/ov_network.go b/libnetwork/drivers/overlay/ov_network.go index 3a4ea41bfc..01f6287bed 100644 --- a/libnetwork/drivers/overlay/ov_network.go +++ b/libnetwork/drivers/overlay/ov_network.go @@ -12,6 +12,7 @@ import ( "strings" "sync" "syscall" + "time" "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/reexec" @@ -705,6 +706,7 @@ func (n *network) initSandbox(restore bool) error { } func (n *network) watchMiss(nlSock *nl.NetlinkSocket) { + t := time.Now() for { msgs, err := nlSock.Receive() if err != nil { @@ -757,23 +759,55 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) { continue } - if !n.driver.isSerfAlive() { - continue - } + if n.driver.isSerfAlive() { + mac, IPmask, vtep, err := n.driver.resolvePeer(n.id, ip) + if err != nil { + logrus.Errorf("could not resolve peer %q: %v", ip, err) + continue + } - mac, IPmask, vtep, err := n.driver.resolvePeer(n.id, ip) - if err != nil { - logrus.Errorf("could not resolve peer %q: %v", ip, err) - continue - } - - if err := n.driver.peerAdd(n.id, "dummy", ip, IPmask, mac, vtep, true, l2Miss, l3Miss); err != nil { - logrus.Errorf("could not add neighbor entry for missed peer %q: %v", ip, err) + if err := n.driver.peerAdd(n.id, "dummy", ip, IPmask, mac, vtep, true, l2Miss, l3Miss); err != nil { + logrus.Errorf("could not add neighbor entry for missed peer %q: %v", ip, err) + } + } else { + // If the gc_thresh values are lower kernel might knock off the neighor entries. + // When we get a L3 miss check if its a valid peer and reprogram the neighbor + // entry again. Rate limit it to once attempt every 500ms, just in case a faulty + // container sends a flood of packets to invalid peers + if !l3Miss { + continue + } + if time.Since(t) > 500*time.Millisecond { + t = time.Now() + n.programNeighbor(ip) + } } } } } +func (n *network) programNeighbor(ip net.IP) { + peerMac, _, _, err := n.driver.peerDbSearch(n.id, ip) + if err != nil { + logrus.Errorf("Reprogramming on L3 miss failed for %s, no peer entry", ip) + return + } + s := n.getSubnetforIPAddr(ip) + if s == nil { + logrus.Errorf("Reprogramming on L3 miss failed for %s, not a valid subnet", ip) + return + } + sbox := n.sandbox() + if sbox == nil { + logrus.Errorf("Reprogramming on L3 miss failed for %s, overlay sandbox missing", ip) + return + } + if err := sbox.AddNeighbor(ip, peerMac, true, sbox.NeighborOptions().LinkName(s.vxlanName)); err != nil { + logrus.Errorf("Reprogramming on L3 miss failed for %s: %v", ip, err) + return + } +} + func (d *driver) addNetwork(n *network) { d.Lock() d.networks[n.id] = n @@ -1052,6 +1086,15 @@ func (n *network) contains(ip net.IP) bool { return false } +func (n *network) getSubnetforIPAddr(ip net.IP) *subnet { + for _, s := range n.subnets { + if s.subnetIP.Contains(ip) { + return s + } + } + return nil +} + // getSubnetforIP returns the subnet to which the given IP belongs func (n *network) getSubnetforIP(ip *net.IPNet) *subnet { for _, s := range n.subnets {