-
Notifications
You must be signed in to change notification settings - Fork 652
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
Conversation
There was a problem hiding this 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.
There was a problem hiding this 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 newtyp 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 includingprog_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 onRawLink.typ
to figure out which flattened struct has to be used and passes pointers if necessary. If no input arguments are required we can usesys.LinkInfo
and parse from .Extra. The result of the syscall is broken down intolink.Info
andlink.IterInfo
, etc. as they work now.
internal/sys/types.go
Outdated
} | ||
|
||
type IterLinkInfo struct { | ||
TargetName uint64 |
There was a problem hiding this comment.
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
...
}
There was a problem hiding this comment.
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
internal/sys/types.go
Outdated
type IterLinkInfo struct { | ||
TargetName uint64 | ||
TargetNameLen uint32 | ||
Map struct{ MapId uint32 } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
internal/sys/types.go
Outdated
} | ||
|
||
type RawTracepointLinkInfo struct { | ||
TpName uint64 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
internal/sys/types.go
Outdated
} | ||
|
||
type TracingLinkInfo struct { | ||
AttachType uint32 |
There was a problem hiding this comment.
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")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
internal/sys/types.go
Outdated
|
||
type CgroupLinkInfo struct { | ||
CgroupId uint64 | ||
AttachType uint32 |
There was a problem hiding this comment.
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")
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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.
// RawLinkInfo deprecated: use LinkInfo instead. | |
// RawLinkInfo contains information on a raw link. | |
// | |
// Deprecated: use LinkInfo instead. |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Document added.
@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. |
There was a problem hiding this 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])))) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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])} |
There was a problem hiding this comment.
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:]) |
There was a problem hiding this comment.
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)
.
I removed IterType and RawTracepointType. |
Thanks! |
This PR is related to issue #506