package  syscall 
 
import  ( 
	"sync"  
	"unsafe"  
) 
 
 
func  nlmAlignOf  (msglen  int ) int  { 
	return  (msglen  + NLMSG_ALIGNTO  - 1 ) & ^(NLMSG_ALIGNTO  - 1 ) 
} 
 
 
 
func  rtaAlignOf  (attrlen  int ) int  { 
	return  (attrlen  + RTA_ALIGNTO  - 1 ) & ^(RTA_ALIGNTO  - 1 ) 
} 
 
 
 
type  NetlinkRouteRequest  struct  { 
	Header  NlMsghdr  
	Data    RtGenmsg  
} 
 
func  (rr  *NetlinkRouteRequest ) toWireFormat  () []byte  { 
	b  := make ([]byte , rr .Header .Len ) 
	*(*uint32 )(unsafe .Pointer (&b [0 :4 ][0 ])) = rr .Header .Len  
	*(*uint16 )(unsafe .Pointer (&b [4 :6 ][0 ])) = rr .Header .Type  
	*(*uint16 )(unsafe .Pointer (&b [6 :8 ][0 ])) = rr .Header .Flags  
	*(*uint32 )(unsafe .Pointer (&b [8 :12 ][0 ])) = rr .Header .Seq  
	*(*uint32 )(unsafe .Pointer (&b [12 :16 ][0 ])) = rr .Header .Pid  
	b [16 ] = byte (rr .Data .Family ) 
	return  b  
} 
 
func  newNetlinkRouteRequest  (proto , seq , family  int ) []byte  { 
	rr  := &NetlinkRouteRequest {} 
	rr .Header .Len  = uint32 (NLMSG_HDRLEN  + SizeofRtGenmsg ) 
	rr .Header .Type  = uint16 (proto ) 
	rr .Header .Flags  = NLM_F_DUMP  | NLM_F_REQUEST  
	rr .Header .Seq  = uint32 (seq ) 
	rr .Data .Family  = uint8 (family ) 
	return  rr .toWireFormat () 
} 
 
var  pageBufPool  = &sync .Pool {New : func () any  { 
	b  := make ([]byte , Getpagesize ()) 
	return  &b  
}} 
 
 
 
func  NetlinkRIB  (proto , family  int ) ([]byte , error ) { 
	s , err  := Socket (AF_NETLINK , SOCK_RAW |SOCK_CLOEXEC , NETLINK_ROUTE ) 
	if  err  != nil  { 
		return  nil , err  
	} 
	defer  Close (s ) 
	sa  := &SockaddrNetlink {Family : AF_NETLINK } 
	if  err  := Bind (s , sa ); err  != nil  { 
		return  nil , err  
	} 
	wb  := newNetlinkRouteRequest (proto , 1 , family ) 
	if  err  := Sendto (s , wb , 0 , sa ); err  != nil  { 
		return  nil , err  
	} 
	lsa , err  := Getsockname (s ) 
	if  err  != nil  { 
		return  nil , err  
	} 
	lsanl , ok  := lsa .(*SockaddrNetlink ) 
	if  !ok  { 
		return  nil , EINVAL  
	} 
	var  tab  []byte  
 
	rbNew  := pageBufPool .Get ().(*[]byte ) 
	defer  pageBufPool .Put (rbNew ) 
done : 
	for  { 
		rb  := *rbNew  
		nr , _ , err  := Recvfrom (s , rb , 0 ) 
		if  err  != nil  { 
			return  nil , err  
		} 
		if  nr  < NLMSG_HDRLEN  { 
			return  nil , EINVAL  
		} 
		rb  = rb [:nr ] 
		tab  = append (tab , rb ...) 
		msgs , err  := ParseNetlinkMessage (rb ) 
		if  err  != nil  { 
			return  nil , err  
		} 
		for  _ , m  := range  msgs  { 
			if  m .Header .Seq  != 1  || m .Header .Pid  != lsanl .Pid  { 
				return  nil , EINVAL  
			} 
			if  m .Header .Type  == NLMSG_DONE  { 
				break  done  
			} 
			if  m .Header .Type  == NLMSG_ERROR  { 
				return  nil , EINVAL  
			} 
		} 
	} 
	return  tab , nil  
} 
 
 
type  NetlinkMessage  struct  { 
	Header  NlMsghdr  
	Data    []byte  
} 
 
 
 
func  ParseNetlinkMessage  (b  []byte ) ([]NetlinkMessage , error ) { 
	var  msgs  []NetlinkMessage  
	for  len (b ) >= NLMSG_HDRLEN  { 
		h , dbuf , dlen , err  := netlinkMessageHeaderAndData (b ) 
		if  err  != nil  { 
			return  nil , err  
		} 
		m  := NetlinkMessage {Header : *h , Data : dbuf [:int (h .Len )-NLMSG_HDRLEN ]} 
		msgs  = append (msgs , m ) 
		b  = b [dlen :] 
	} 
	return  msgs , nil  
} 
 
func  netlinkMessageHeaderAndData  (b  []byte ) (*NlMsghdr , []byte , int , error ) { 
	h  := (*NlMsghdr )(unsafe .Pointer (&b [0 ])) 
	l  := nlmAlignOf (int (h .Len )) 
	if  int (h .Len ) < NLMSG_HDRLEN  || l  > len (b ) { 
		return  nil , nil , 0 , EINVAL  
	} 
	return  h , b [NLMSG_HDRLEN :], l , nil  
} 
 
 
type  NetlinkRouteAttr  struct  { 
	Attr   RtAttr  
	Value  []byte  
} 
 
 
 
 
func  ParseNetlinkRouteAttr  (m  *NetlinkMessage ) ([]NetlinkRouteAttr , error ) { 
	var  b  []byte  
	switch  m .Header .Type  { 
	case  RTM_NEWLINK , RTM_DELLINK : 
		b  = m .Data [SizeofIfInfomsg :] 
	case  RTM_NEWADDR , RTM_DELADDR : 
		b  = m .Data [SizeofIfAddrmsg :] 
	case  RTM_NEWROUTE , RTM_DELROUTE : 
		b  = m .Data [SizeofRtMsg :] 
	default : 
		return  nil , EINVAL  
	} 
	var  attrs  []NetlinkRouteAttr  
	for  len (b ) >= SizeofRtAttr  { 
		a , vbuf , alen , err  := netlinkRouteAttrAndValue (b ) 
		if  err  != nil  { 
			return  nil , err  
		} 
		ra  := NetlinkRouteAttr {Attr : *a , Value : vbuf [:int (a .Len )-SizeofRtAttr ]} 
		attrs  = append (attrs , ra ) 
		b  = b [alen :] 
	} 
	return  attrs , nil  
} 
 
func  netlinkRouteAttrAndValue  (b  []byte ) (*RtAttr , []byte , int , error ) { 
	a  := (*RtAttr )(unsafe .Pointer (&b [0 ])) 
	if  int (a .Len ) < SizeofRtAttr  || int (a .Len ) > len (b ) { 
		return  nil , nil , 0 , EINVAL  
	} 
	return  a , b [SizeofRtAttr :], rtaAlignOf (int (a .Len )), nil  
} 
  
The pages are generated with Golds   v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds  is a Go 101  project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1  (reachable from the left QR code) to get the latest news of Golds .