Skip to content

Commit

Permalink
Merge pull request #9093 from sridhartigera/cherry-pick-host-ip-ebpf
Browse files Browse the repository at this point in the history
[v3.27]Fix host IP parsing in eBPF and re-attach programs when host IP changes
  • Loading branch information
sridhartigera authored Aug 2, 2024
2 parents 578d71d + 395d06b commit 71dcab0
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 15 deletions.
19 changes: 13 additions & 6 deletions felix/dataplane/linux/bpf_ep_mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -652,14 +652,21 @@ func (m *bpfEndpointManager) GetIfaceQDiscInfo(ifaceName string) (bool, int, int
return qdisc.valid, qdisc.prio, qdisc.handle
}

func (m *bpfEndpointManager) updateHostIP(ip net.IP) {
func (m *bpfEndpointManager) updateHostIP(ipAddr string) {
ip, _, err := net.ParseCIDR(ipAddr)
if err != nil {
ip = net.ParseIP(ipAddr)
}
if ip != nil {
m.hostIP = ip
// Should be safe without the lock since there shouldn't be any active background threads
// but taking it now makes us robust to refactoring.
m.ifacesLock.Lock()
for ifaceName := range m.nameToIface {
m.dirtyIfaceNames.Add(ifaceName)
m.withIface(ifaceName, func(iface *bpfInterface) (forceDirty bool) {
iface.dpState.readiness = ifaceNotReady
return true
})
}
m.ifacesLock.Unlock()
} else {
Expand Down Expand Up @@ -697,23 +704,23 @@ func (m *bpfEndpointManager) OnUpdate(msg interface{}) {
case *proto.HostMetadataUpdate:
if !m.ipv6Enabled && msg.Hostname == m.hostname {
log.WithField("HostMetadataUpdate", msg).Infof("Host IP changed: %s", msg.Ipv4Addr)
m.updateHostIP(net.ParseIP(msg.Ipv4Addr))
m.updateHostIP(msg.Ipv4Addr)
}
case *proto.HostMetadataV6Update:
if m.ipv6Enabled && msg.Hostname == m.hostname {
log.WithField("HostMetadataV6Update", msg).Infof("Host IPv6 changed: %s", msg.Ipv6Addr)
m.updateHostIP(net.ParseIP(msg.Ipv6Addr))
m.updateHostIP(msg.Ipv6Addr)
}
case *proto.HostMetadataV4V6Update:
if msg.Hostname != m.hostname {
break
}
if m.ipv6Enabled {
log.WithField("HostMetadataV4V6Update", msg).Infof("Host IPv6 changed: %s", msg.Ipv6Addr)
m.updateHostIP(net.ParseIP(msg.Ipv6Addr))
m.updateHostIP(msg.Ipv6Addr)
} else {
log.WithField("HostMetadataV4V6Update", msg).Infof("Host IP changed: %s", msg.Ipv4Addr)
m.updateHostIP(net.ParseIP(msg.Ipv4Addr))
m.updateHostIP(msg.Ipv4Addr)
}
case *proto.ServiceUpdate:
m.onServiceUpdate(msg)
Expand Down
58 changes: 49 additions & 9 deletions felix/dataplane/linux/bpf_ep_mgr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ import (
)

type mockDataplane struct {
mutex sync.Mutex
lastProgID int
progs map[string]int
policy map[string]polprog.Rules
routes map[ip.CIDR]struct{}
mutex sync.Mutex
lastProgID int
progs map[string]int
numAttaches map[string]int
policy map[string]polprog.Rules
routes map[ip.CIDR]struct{}

ensureStartedFn func()
ensureQdiscFn func(string) (bool, error)
Expand All @@ -71,10 +72,11 @@ type mockDataplane struct {

func newMockDataplane() *mockDataplane {
return &mockDataplane{
lastProgID: 5,
progs: map[string]int{},
policy: map[string]polprog.Rules{},
routes: map[ip.CIDR]struct{}{},
lastProgID: 5,
progs: map[string]int{},
numAttaches: map[string]int{},
policy: map[string]polprog.Rules{},
routes: map[ip.CIDR]struct{}{},
}
}

Expand Down Expand Up @@ -114,6 +116,7 @@ func (m *mockDataplane) ensureProgramAttached(ap attachPoint) (bpf.AttachResult,
}

key := ap.IfaceName() + ":" + ap.HookName().String()
m.numAttaches[key] = m.numAttaches[key] + 1
if _, exists := m.progs[key]; exists {
return res, nil
}
Expand Down Expand Up @@ -189,6 +192,12 @@ func (m *mockDataplane) programAttached(key string) bool {
return m.progs[key] != 0
}

func (m *mockDataplane) numOfAttaches(key string) int {
m.mutex.Lock()
defer m.mutex.Unlock()
return m.numAttaches[key]
}

func (m *mockDataplane) setRoute(cidr ip.CIDR) {
m.mutex.Lock()
defer m.mutex.Unlock()
Expand Down Expand Up @@ -439,6 +448,17 @@ var _ = Describe("BPF Endpoint Manager", func() {
}
}

genHostMetadataUpdate := func(ip string) func() {
return func() {
bpfEpMgr.OnUpdate(&proto.HostMetadataUpdate{
Hostname: "uthost",
Ipv4Addr: ip,
})
err := bpfEpMgr.CompleteDeferredWork()
Expect(err).NotTo(HaveOccurred())
}
}

hostEp := proto.HostEndpoint{
Name: "uthost-eth0",
PreDnatTiers: []*proto.TierInfo{
Expand Down Expand Up @@ -537,6 +557,26 @@ var _ = Describe("BPF Endpoint Manager", func() {
})
})

Context("with workload endpoints", func() {
JustBeforeEach(func() {
genWLUpdate("cali12345")()
genIfaceUpdate("cali12345", ifacemonitor.StateUp, 15)()
})

It("must re-attach programs when hostIP changes", func() {
Expect(dp.programAttached("cali12345:ingress")).To(BeTrue())
Expect(dp.programAttached("cali12345:egress")).To(BeTrue())
Expect(dp.numOfAttaches("cali12345:ingress")).To(Equal(1))
Expect(dp.numOfAttaches("cali12345:egress")).To(Equal(1))
genHostMetadataUpdate("5.6.7.8/32")()
Expect(dp.numOfAttaches("cali12345:ingress")).To(Equal(2))
Expect(dp.numOfAttaches("cali12345:egress")).To(Equal(2))
genHostMetadataUpdate("1.2.3.4")()
Expect(dp.numOfAttaches("cali12345:ingress")).To(Equal(3))
Expect(dp.numOfAttaches("cali12345:egress")).To(Equal(3))
})
})

Context("with eth0 up", func() {
JustBeforeEach(func() {
genPolicy("default", "mypolicy")()
Expand Down

0 comments on commit 71dcab0

Please sign in to comment.