Make virtual service programming more robust

- Do not relay on software flags to decide when to create the
   virtual service. Instead query the kernel for presence.
   So that it cannot happen that a real server creation
   fails because the virtual server is missing.

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2017-02-01 14:55:39 -08:00
parent f318ddacdb
commit 4e69afc4f3
5 changed files with 17 additions and 23 deletions

View file

@ -42,6 +42,7 @@ type Destination struct {
// Handle provides a namespace specific ipvs handle to program ipvs
// rules.
type Handle struct {
seq uint32
sock *nl.NetlinkSocket
}
@ -82,6 +83,11 @@ func (i *Handle) NewService(s *Service) error {
return i.doCmd(s, nil, ipvsCmdNewService)
}
// IsServicePresent queries for the ipvs service in the passed handle.
func (i *Handle) IsServicePresent(s *Service) bool {
return nil == i.doCmd(s, nil, ipvsCmdGetService)
}
// UpdateService updates an already existing service in the passed
// handle.
func (i *Handle) UpdateService(s *Service) error {

View file

@ -10,6 +10,7 @@ import (
"os/exec"
"strings"
"sync"
"sync/atomic"
"syscall"
"unsafe"
@ -118,6 +119,7 @@ func fillDestinaton(d *Destination) nl.NetlinkRequestData {
func (i *Handle) doCmd(s *Service, d *Destination, cmd uint8) error {
req := newIPVSRequest(cmd)
req.Seq = atomic.AddUint32(&i.seq, 1)
req.AddData(fillService(s))
if d != nil {
@ -206,7 +208,7 @@ done:
}
for _, m := range msgs {
if m.Header.Seq != req.Seq {
return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
continue
}
if m.Header.Pid != pid {
return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)

View file

@ -61,11 +61,6 @@ func (c *controller) cleanupServiceBindings(cleanupNID string) {
}
func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, ingressPorts []*PortConfig, aliases []string, ip net.IP) error {
var (
s *service
addService bool
)
n, err := c.NetworkByID(nid)
if err != nil {
return err
@ -123,11 +118,6 @@ func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, i
fwMarkCtrMu.Unlock()
s.loadBalancers[nid] = lb
// Since we just created this load balancer make sure
// we add a new service service in IPVS rules.
addService = true
}
lb.backEnds[eid] = ip
@ -135,7 +125,7 @@ func (c *controller) addServiceBinding(name, sid, nid, eid string, vip net.IP, i
// Add loadbalancer service and backend in all sandboxes in
// the network only if vip is valid.
if len(vip) != 0 {
n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts, addService)
n.(*network).addLBBackend(ip, vip, lb.fwMark, ingressPorts)
}
return nil

View file

@ -97,20 +97,16 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) {
}
lb.service.Lock()
addService := true
for _, ip := range lb.backEnds {
sb.addLBBackend(ip, lb.vip, lb.fwMark, lb.service.ingressPorts,
eIP, gwIP, addService, n.ingress)
addService = false
sb.addLBBackend(ip, lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, gwIP, n.ingress)
}
lb.service.Unlock()
}
}
// Add loadbalancer backend to all sandboxes which has a connection to
// this network. If needed add the service as well, as specified by
// the addService bool.
func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, addService bool) {
// this network. If needed add the service as well.
func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig) {
n.WalkEndpoints(func(e Endpoint) bool {
ep := e.(*endpoint)
if sb, ok := ep.getSandbox(); ok {
@ -123,7 +119,7 @@ func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po
gwIP = ep.Iface().Address().IP
}
sb.addLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, addService, n.ingress)
sb.addLBBackend(ip, vip, fwMark, ingressPorts, ep.Iface().Address(), gwIP, n.ingress)
}
return false
@ -154,7 +150,7 @@ func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Por
}
// Add loadbalancer backend into one connected sandbox.
func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, gwIP net.IP, addService bool, isIngressNetwork bool) {
func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, gwIP net.IP, isIngressNetwork bool) {
if sb.osSbox == nil {
return
}
@ -176,7 +172,7 @@ func (sb *sandbox) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*P
SchedName: ipvs.RoundRobin,
}
if addService {
if !i.IsServicePresent(s) {
var filteredPorts []*PortConfig
if sb.ingress {
filteredPorts = filterPortConfigs(ingressPorts, false)

View file

@ -2,7 +2,7 @@ package libnetwork
import "net"
func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, addService bool) {
func (n *network) addLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig) {
}
func (n *network) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, rmService bool) {