Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance bpf interface autodetection #9498

Merged

Conversation

sridhartigera
Copy link
Member

@sridhartigera sridhartigera commented Nov 18, 2024

Description

This PR enhances the host interface auto-detection logic for the eBPF dataplane.
with the new approach, BPF endpoint manager builds a set of trees based on the netlink information of each host interface.

For example, if we have 2 interfaces in a bond and vlan on top of the bond, vlan interface is at the root of the tree, bond is at level 1 and physical interfaces are at the leaves. In the case of single standalone interfaces, each interface is a single node tree. Attaching Tc,XDP programs follows the below logic

  1. If the interface is a root node, attach Tc.
  2. If the interface is a leaf node, attach XDP.
  3. If the interface is neither root nor leaf, it is ignored.

In the above process, XDP and Tc programs are removed from the interfaces when the interface moves down the tree.

bpftool net
xdp:
enp1s0f0np0(2) driver id 965
enp1s0f1np1(4) driver id 968

tc:
lo(1) clsact/ingress cali_tc_preambl:[804] id 804
lo(1) clsact/egress cali_tc_preambl:[805] id 805
bond0.1001(6) clsact/ingress cali_tc_preambl:[974] id 974
bond0.1001(6) clsact/egress cali_tc_preambl:[976] id 976
bpfout.cali(7) clsact/ingress cali_tc_preambl:[844] id 844
bpfout.cali(7) clsact/egress cali_tc_preambl:[843] id 843
cali662a7526402(9) clsact/ingress cali_tc_preambl:[894] id 894
cali662a7526402(9) clsact/egress cali_tc_preambl:[895] id 895
vxlan.calico(10) clsact/ingress cali_tc_preambl:[823] id 823
vxlan.calico(10) clsact/egress cali_tc_preambl:[822] id 822
cali596936e74c1(11) clsact/ingress cali_tc_preambl:[896] id 896
cali596936e74c1(11) clsact/egress cali_tc_preambl:[889] id 889
calie500d5708cd(12) clsact/ingress cali_tc_preambl:[890] id 890
calie500d5708cd(12) clsact/egress cali_tc_preambl:[891] id 891

xdp attached to physical interface and tc to bond.vlan

Related issues/PRs

Todos

  • Tests
  • Documentation
  • Release note

Release Note

ebpf: improved autodetection of device hierarchy like bonds and vlans. tc is attached to the root and xdp to the leaves.

Reminder for the reviewer

Make sure that this PR has the correct labels and milestone set.

Every PR needs one docs-* label.

  • docs-pr-required: This change requires a change to the documentation that has not been completed yet.
  • docs-completed: This change has all necessary documentation completed.
  • docs-not-required: This change has no user-facing impact and requires no docs.

Every PR needs one release-note-* label.

  • release-note-required: This PR has user-facing changes. Most PRs should have this label.
  • release-note-not-required: This PR has no user-facing changes.

Other optional labels:

  • cherry-pick-candidate: This PR should be cherry-picked to an earlier release. For bug fixes only.
  • needs-operator-pr: This PR is related to install and requires a corresponding change to the operator.

@marvin-tigera marvin-tigera added this to the Calico v3.30.0 milestone Nov 18, 2024
@marvin-tigera marvin-tigera added release-note-required Change has user-facing impact (no matter how small) docs-pr-required Change is not yet documented labels Nov 18, 2024
@CLAassistant
Copy link

CLAassistant commented Nov 26, 2024

CLA assistant check
All committers have signed the CLA.

@sridhartigera sridhartigera marked this pull request as ready for review November 27, 2024 19:21
@sridhartigera sridhartigera requested a review from a team as a code owner November 27, 2024 19:21
@@ -1122,87 +1131,37 @@ func (m *bpfEndpointManager) onInterfaceUpdate(update *ifaceStateUpdate) {
return
}

// Should be safe without the lock since there shouldn't be any active background threads
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you move this down here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I take the lock in cleanupOldAttach to get the policyIdx info from the state. Hence moved the lock in the calling function below the block where we call cleanupOldAttach

if _, ok := m.hostIfaceToSlaveDevices[netiface.Name]; !ok {
m.hostIfaceToSlaveDevices[netiface.Name] = set.New[string]()
log.Errorf("Failed to get interface information via netlink '%s'", update.Name)
curIfaceType = IfaceTypeL3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we default to L3?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when we don't get the link information, I default the type to L3 and if the interface matches in dataIfacePattern, I change it to Data.

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
Comment on lines 218 to 219
masterIndex int
parentIndex int
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can the interface have both master and parent in the tree? It feels to me that that the system ifaces can have either or, but not both and it is just a naming convention. I wonder if it would make thing simple if we maintained only a parent for both in our internal tree. Or maybe I am confused since there is just one parent pointer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

master and parent index are treated differently. With the refactoring I just have the masterIndex. This is used only for cases when the interface moves out of a bond. The interface will be a child of the bond and when it moves out, it needs to be added as a standalone interface.


if attrs.MasterIndex == 0 && attrs.ParentIndex == 0 {
eintf := m.findHostIfaceByIndex(attrs.Index)
if eintf != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so a device with this index already exists. If you think it is the same device, why would you rewrite its name etc, but not the parent. children etc?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just rewrite the name so that I don't overwrite the children information. For example, when felix gets the child information first, we create the child node and also the parent node with master index. Now when felix gets the update of the parent interface, the interface with that index is already there in the tree. Just need to update the name.

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
@@ -305,6 +314,7 @@ type bpfEndpointManager struct {
ifStateMap *cachingmap.CachingMap[ifstate.Key, ifstate.Value]
removeOldJumps bool
legacyCleanUp bool
hostIfaces map[int]*bpfHostIface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems that hostIfaces are the roots of the trees, but then you use findHostIfaceByIndex that is returning ifaces that are not in this map, but within the trees. It is quite confusing.

What if this map was called hepIfaces or hostIfaceTrees or whatever would show that it is not just a plain interface

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed it to hostIfaceTrees and introduced a new type bpfIfaceTrees

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
link, err := m.dp.getIfaceLink(masterIfName)
if err != nil {
log.Errorf("Error getting link for interface %s, err = %v", masterIfName, err)
return slaveDevices
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be like a nil or something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have changed to return an empty slice of string.

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
m.hostIfaces[attrs.MasterIndex] = masterIface
}
}
delete(m.hostIfaces, attrs.Index)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you deleting it if you just added it and it could be the new root?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When adding an interface with masterIndex !=0 (which means the intf is a slave intf), we need to delete the interface from the tree before adding it because the interface might have moved from standalone to a bond. Hence the deletion.

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
Comment on lines +4430 to +4436
for _, child := range hostIf.children {
if child.name != "" {
return false
}
}
return true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for _, child := range hostIf.children {
if child.name != "" {
return false
}
}
return true
return len(hostIf.children) == 0

perhaps?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In our FVs, eth0 is a veth which has a parent index. Hence the parent interface will be added as a child but it wont have a name, since felix wont get the update. This results in len(hostIf.children) > 0 but its a invalid child. Hence I did not do this way.

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
Copy link
Contributor

@tomastigera tomastigera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have come mostly naming nits, lgtm in general

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
if val.masterIndex != 0 {
h.deleteIface(intf.name)
} else {
// We might have created this interface.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does it mean?

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
Comment on lines 4263 to 4265
// Better to delete the interface here. Now the interface is a slave interface.
// Its highly likely that it has moved from standalone to a slave. Hence delete the
// interface from the tree and add it again.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Better to delete the interface here. Now the interface is a slave interface.
// Its highly likely that it has moved from standalone to a slave. Hence delete the
// interface from the tree and add it again.
// Now the interface is a slave interface, perhaps with a different master. So delete the interface and add it again.

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
}
}

// addIfaceWithParent handles adding interface with parentIndex to the tree.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// addIfaceWithParent handles adding interface with parentIndex to the tree.
// addIfaceWithParent add in-tree parent of the parentIndex interface.

felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
felix/dataplane/linux/bpf_ep_mgr.go Outdated Show resolved Hide resolved
@sridhartigera sridhartigera merged commit 79e50f1 into projectcalico:master Dec 19, 2024
3 checks passed
@sridhartigera sridhartigera deleted the bpf-iface-autodetect branch December 19, 2024 00:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs-pr-required Change is not yet documented release-note-required Change has user-facing impact (no matter how small)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants