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

link: expose link info with type-specific information #509

Merged
merged 5 commits into from
Dec 17, 2021
Merged

link: expose link info with type-specific information #509

merged 5 commits into from
Dec 17, 2021

Conversation

mehrdadrad
Copy link
Contributor

This PR is related to issue #506

  • add new method: Info() (*RawLinkInfo, error) to Link interface.
  • add bpf_link_info union member types to types generator.
  • update sys/types with generator.
  • add info method to types that they don't support.
  • enhance a few tests to cover info. (needs to add more)
  • fix NetNsInfo type.

Copy link
Collaborator

@lmb lmb left a comment

Choose a reason for hiding this comment

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

This is quite nice! Shoving the extra interface{} in there is a good idea, thanks for that.

internal/sys/types.go Outdated Show resolved Hide resolved
internal/cmd/gentypes/main.go Outdated Show resolved Hide resolved
internal/cmd/gentypes/main.go Outdated Show resolved Hide resolved
internal/cmd/gentypes/main.go Outdated Show resolved Hide resolved
internal/cmd/gentypes/main.go Outdated Show resolved Hide resolved
link/link.go Outdated Show resolved Hide resolved
link/link.go Outdated Show resolved Hide resolved
link/link.go Outdated Show resolved Hide resolved
link/link.go Outdated Show resolved Hide resolved
link/netns.go Outdated Show resolved Hide resolved
@mehrdadrad mehrdadrad marked this pull request as ready for review December 8, 2021 06:05
@mehrdadrad mehrdadrad requested a review from lmb December 8, 2021 06:05
Copy link
Collaborator

@lmb lmb left a comment

Choose a reason for hiding this comment

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

I realised now that LinkInfo.Extra being a blob of bytes is a problem: we can't specify input arguments to BPF_OBJ_GET_INFO_BY_FD. This means we can never pass a pointer to the kernel to retrieve things, for example IterLinkInfo.TargetName. It also means that we have to know the link type to be able to retrieve info from the kernel. 🤦

I think we'll have to do the following:

  • link.RawLink needs a new typ link.Type field which is populated when creating a link and when LoadPinnedLink is called.
  • For link info types that require input arguments we generate a flattened struct bpf_link_info. This means including prog_id etc. sys.IterLinkInfo is an example of this.
  • Each link type has a dedicated link.IterInfo, link.NetNsInfo, etc. struct which basically contains the info specific to that link type (with pointer, length pairs replaced with strings, etc.)
  • RawLink.Info() switches on RawLink.typ to figure out which flattened struct has to be used and passes pointers if necessary. If no input arguments are required we can use sys.LinkInfo and parse from .Extra. The result of the syscall is broken down into link.Info and link.IterInfo, etc. as they work now.

internal/cmd/gentypes/main.go Show resolved Hide resolved
}

type IterLinkInfo struct {
TargetName uint64
Copy link
Collaborator

Choose a reason for hiding this comment

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

This needs to be a Pointer so you'll need to do some replacements after all. Something like replace(pointer, "target_name"). This also tells me that we need wrapper types in Link: we shouldn't expose raw pointer and length to the user. link.IterInfo should be:

struct IterInfo {
    TargetName string
    ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IterInfo and RawTracepointInfo added.

type RawTracepointInfo struct {
	TPName string
}
type IterInfo struct {
	TargetName string
}

Also I added the below types (not alias):

type TracingInfo sys.TracingLinkInfo
type CgroupInfo sys.CgroupLinkInfo
type NetNsInfo sys.NetNsLinkInfo
type XDPInfo sys.XDPLinkInfo

type IterLinkInfo struct {
TargetName uint64
TargetNameLen uint32
Map struct{ MapId uint32 }
Copy link
Collaborator

Choose a reason for hiding this comment

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

The C type for this looks like so:

			union {
				struct {
					__u32 map_id;
				} map;
			};

This probably means that the result is polymorphic depending on the iter type. So really this would need another layer of Extra type unwrapping. Let's truncateAfter("target_name_len") and punt on this problem for now until someone comes along and wants access to the field.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

truncateAfter("target_name_len") added.

}

type RawTracepointLinkInfo struct {
TpName uint64
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also needs a pointer replace.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.

}

type TracingLinkInfo struct {
AttachType uint32
Copy link
Collaborator

Choose a reason for hiding this comment

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

Needs replace(enumTypes["AttachType"], "attach_type")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.


type CgroupLinkInfo struct {
CgroupId uint64
AttachType uint32
Copy link
Collaborator

Choose a reason for hiding this comment

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

Needs replace(enumTypes["AttachType"], "attach_type")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.

link/link.go Outdated
extra interface{}
}

// RawLinkInfo deprecated: use LinkInfo instead.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the Deprecated has to be on it's own line for linters to do their work.

Suggested change
// RawLinkInfo deprecated: use LinkInfo instead.
// RawLinkInfo contains information on a raw link.
//
// Deprecated: use LinkInfo instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.

link/link.go Outdated
// RawLinkInfo contains metadata on a link.
type RawLinkInfo struct {
// LinkInfo contains metadata on a link.
type LinkInfo struct {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: this reads link.LinkInfo, link.Info is better imo.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed.

link/link.go Outdated
// RawLinkInfo deprecated: use LinkInfo instead.
type RawLinkInfo = LinkInfo

func (r LinkInfo) ExtraRawTracepoint() *sys.RawTracepointLinkInfo {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I was thinking of returning (*RawInfo, bool) but I guess this works too. Can you document that the functions can return nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Document added.

internal/cmd/gentypes/main.go Outdated Show resolved Hide resolved
@mehrdadrad
Copy link
Contributor Author

I realised now that LinkInfo.Extra being a blob of bytes is a problem: we can't specify input arguments to BPF_OBJ_GET_INFO_BY_FD. This means we can never pass a pointer to the kernel to retrieve things, for example IterLinkInfo.TargetName. It also means that we have to know the link type to be able to retrieve info from the kernel. 🤦

@lmb I fixed the pass a pointer to the kernel through bytes please review it. I think this way we have less code and less complexity. I addressed other feedbacks as well.

@mehrdadrad mehrdadrad requested a review from lmb December 10, 2021 07:12
Copy link
Collaborator

@lmb lmb left a comment

Choose a reason for hiding this comment

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

Manually encoding pointers into LinkInfo.Extra is problematic, I'm not sure how to best handle this at the moment. Could you get along without RawTracepointInfo and IterInfo? If we can skip these two the PR is good to go, otherwise it needs a bunch more work.

link/link.go Outdated
var info sys.LinkInfo

name := make([]byte, 128)
internal.NativeEndian.PutUint64(info.Extra[:], uint64(uintptr(unsafe.Pointer(&name[0]))))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm kind of surprised that this works, I'd have thought that the kernel will refuse link info with garbage in the input.

This doesn't take arch differences between pointers into account, so this may break on 32 bit / big endian (shudder) arches. See ptr_64.go, ptr_32_le.go, etc. Finally, it took me a while to figure out that the GC won't just free name, it's a bit too subtle for me.

link/link.go Outdated
var info sys.LinkInfo

name := make([]byte, 128)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Assuming size < 128 is incorrect, see below re nameLen.

link/link.go Outdated
switch info.Type {
case RawTracepointType:
nameLen := internal.NativeEndian.Uint32(info.Extra[8:])
extra = &RawTracepointInfo{TPName: string(name[:nameLen])}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Per bpf_raw_tp_link_fill_link_info this is zero terminated, so you need to use unix.ByteSliceToString.

link/link.go Outdated
var extra interface{}
switch info.Type {
case RawTracepointType:
nameLen := internal.NativeEndian.Uint32(info.Extra[8:])
Copy link
Collaborator

Choose a reason for hiding this comment

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

The kernel writes the real length of TPName into nameLen, so this can be longer than len(name). Therefore name[:nameLen] can panic. To handle this correctly you have to retry the syscall with a larger allocated buffer. The current layout of the code doesn't lend itself for that unfortunately. My suggestion: return an error if nameLen >= len(name).

@mehrdadrad
Copy link
Contributor Author

Manually encoding pointers into LinkInfo.Extra is problematic, I'm not sure how to best handle this at the moment. Could you get along without RawTracepointInfo and IterInfo? If we can skip these two the PR is good to go, otherwise it needs a bunch more work.

I removed IterType and RawTracepointType.

@lmb lmb merged commit 642df39 into cilium:master Dec 17, 2021
@lmb
Copy link
Collaborator

lmb commented Dec 17, 2021

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants