@@ -2,15 +2,9 @@ package netlink
22
33import  (
44	"fmt" 
5- 	"io" 
65	"log" 
76	"os" 
8- 	"strconv" 
97	"strings" 
10- 	"syscall" 
11- 	"unsafe" 
12- 
13- 	"github.com/mdlayher/netlink/nlenc" 
148)
159
1610// Arguments used to create a debugger. 
@@ -33,230 +27,15 @@ type debugger struct {
3327	Format  string 
3428}
3529
36- // newDebugger creates a debugger by parsing key=value arguments. 
37- func  newDebugger (args  []string ) * debugger  {
38- 	d  :=  & debugger {
39- 		Log :   log .New (os .Stderr , "nl: " , 0 ),
40- 		Level : 1 ,
41- 	}
42- 
43- 	for  _ , a  :=  range  args  {
44- 		kv  :=  strings .Split (a , "=" )
45- 		if  len (kv ) !=  2  {
46- 			// Ignore malformed pairs and assume callers wants defaults. 
47- 			continue 
48- 		}
49- 
50- 		switch  kv [0 ] {
51- 		// Select the log level for the debugger. 
52- 		case  "level" :
53- 			level , err  :=  strconv .Atoi (kv [1 ])
54- 			if  err  !=  nil  {
55- 				panicf ("netlink: invalid NLDEBUG level: %q" , a )
56- 			}
57- 
58- 			d .Level  =  level 
59- 		case  "format" :
60- 			d .Format  =  kv [1 ]
61- 		}
62- 	}
63- 
64- 	return  d 
65- }
66- 
67- // debugf prints debugging information at the specified level, if d.Level is 
68- // high enough to print the message. 
69- func  (d  * debugger ) debugf (level  int , format  string , v  ... interface {}) {
70- 	if  d .Level  >=  level  {
71- 		if  d .Format  ==  "mnl"  {
72- 			for  _ , iface  :=  range  v  {
73- 				if  msg , ok  :=  iface .(Message ); ok  {
74- 					nlmsgFprintf (d .Log .Writer (), msg )
75- 				}
76- 			}
77- 		} else  {
78- 			d .Log .Printf (format , v ... )
79- 		}
80- 	}
81- }
82- 
30+ // panicf is a helper to panic with formatted text. 
8331func  panicf (format  string , a  ... interface {}) {
8432	panic (fmt .Sprintf (format , a ... ))
8533}
8634
87- /* 
88- 	nlmsgFprintf - print netlink message to file 
89- 	- Based on https://git.netfilter.org/libmnl/tree/src/nlmsg.c 
90- 	- This function prints the netlink header to a file handle. 
91- 	- It may be useful for debugging purposes. One example of the output 
92- 	- is the following: 
93- 
94- ----------------        ------------------ 
95- |  0000000040  |        | message length | 
96- | 00016 | R-A- |        |  type | flags  | 
97- |  1289148991  |        | sequence number| 
98- |  0000000000  |        |     port ID    | 
99- ----------------        ------------------ 
100- | 00 00 00 00  |        |  extra header  | 
101- | 00 00 00 00  |        |  extra header  | 
102- | 01 00 00 00  |        |  extra header  | 
103- | 01 00 00 00  |        |  extra header  | 
104- |00008|--|00003|        |len |flags| type| 
105- | 65 74 68 30  |        |      data      |       e t h 0 
106- ----------------        ------------------ 
107- 
108- 	* 
109- 	* This example above shows the netlink message that is send to kernel-space 
110- 	* to set up the link interface eth0. The netlink and attribute header data 
111- 	* are displayed in base 10 whereas the extra header and the attribute payload 
112- 	* are expressed in base 16. The possible flags in the netlink header are: 
113- 	* 
114- 	* - R, that indicates that NLM_F_REQUEST is set. 
115- 	* - M, that indicates that NLM_F_MULTI is set. 
116- 	* - A, that indicates that NLM_F_ACK is set. 
117- 	* - E, that indicates that NLM_F_ECHO is set. 
118- 	* 
119- 	* The lack of one flag is displayed with '-'. On the other hand, the possible 
120- 	* attribute flags available are: 
121- 	* 
122- 	* - N, that indicates that NLA_F_NESTED is set. 
123- 	* - B, that indicates that NLA_F_NET_BYTEORDER is set. 
124- */ 
125- func  nlmsgFprintfHeader (fd  io.Writer , nlh  Header ) {
126- 	fmt .Fprintf (fd , "----------------\t ------------------\n " )
127- 	fmt .Fprintf (fd , "|  %010d  |\t | message length |\n " , nlh .Length )
128- 	fmt .Fprintf (fd , "| %05d | %s%s%s%s |\t |  type | flags  |\n " ,
129- 		nlh .Type ,
130- 		ternary (nlh .Flags & Request  !=  0 , "R" , "-" ),
131- 		ternary (nlh .Flags & Multi  !=  0 , "M" , "-" ),
132- 		ternary (nlh .Flags & Acknowledge  !=  0 , "A" , "-" ),
133- 		ternary (nlh .Flags & Echo  !=  0 , "E" , "-" ),
134- 	)
135- 	fmt .Fprintf (fd , "|  %010d   |\t | sequence number|\n " , nlh .Sequence )
136- 	fmt .Fprintf (fd , "|  %010d  |\t |     port ID    |\n " , nlh .PID )
137- 	fmt .Fprintf (fd , "----------------\t ------------------\n " )
138- }
139- 
140- // nlmsgFprintf checks a single Message for netlink errors. 
141- func  nlmsgFprintf (fd  io.Writer , m  Message ) {
142- 	colorize  :=  true 
143- 	var  hasHeader  bool 
144- 	nlmsgFprintfHeader (fd , m .Header )
145- 	switch  {
146- 	case  m .Header .Type  ==  Error :
147- 		hasHeader  =  true 
148- 	case  m .Header .Type  ==  Done  &&  m .Header .Flags & Multi  !=  0 :
149- 		if  len (m .Data ) ==  0  {
150- 			return 
151- 		}
152- 	default :
153- 		// Neither, nothing to do. 
154- 	}
155- 
156- 	// Errno occupies 4 bytes. 
157- 	const  endErrno  =  4 
158- 	if  len (m .Data ) <  endErrno  {
159- 		return 
160- 	}
161- 
162- 	c  :=  nlenc .Int32 (m .Data [:endErrno ])
163- 	if  c  !=  0  {
164- 		b  :=  m .Data [0 :4 ]
165- 		fmt .Fprintf (fd , "| %.2x %.2x %.2x %.2x  |\t " ,
166- 			0xff & b [0 ], 0xff & b [1 ],
167- 			0xff & b [2 ], 0xff & b [3 ])
168- 		fmt .Fprintf (fd , "|  extra header  |\n " )
169- 	}
170- 
171- 	// Flags indicate an extended acknowledgement. The type/flags combination 
172- 	// checked above determines the offset where the TLVs occur. 
173- 	var  off  int 
174- 	if  hasHeader  {
175- 		// There is an nlmsghdr preceding the TLVs. 
176- 		if  len (m .Data ) <  endErrno + nlmsgHeaderLen  {
177- 			return 
178- 		}
179- 
180- 		// The TLVs should be at the offset indicated by the nlmsghdr.length, 
181- 		// plus the offset where the header began. But make sure the calculated 
182- 		// offset is still in-bounds. 
183- 		h  :=  * (* Header )(unsafe .Pointer (& m .Data [endErrno  : endErrno + nlmsgHeaderLen ][0 ]))
184- 		off  =  endErrno  +  int (h .Length )
185- 
186- 		if  len (m .Data ) <  off  {
187- 			return 
188- 		}
189- 	} else  {
190- 		// There is no nlmsghdr preceding the TLVs, parse them directly. 
191- 		off  =  endErrno 
192- 	}
193- 
194- 	data  :=  m .Data [off :]
195- 	for  i  :=  0 ; i  <  len (data ); {
196- 		// Make sure there's at least a header's worth 
197- 		// of data to read on each iteration. 
198- 		if  len (data [i :]) <  nlaHeaderLen  {
199- 			break 
200- 		}
201- 
202- 		// Extract the length of the attribute. 
203- 		l  :=  int (nlenc .Uint16 (data [i  : i + 2 ]))
204- 		// extract the type 
205- 		t  :=  nlenc .Uint16 (data [i + 2  : i + 4 ])
206- 		// print attribute header 
207- 		if  colorize  {
208- 			fmt .Fprintf (fd , "|\033 [1;31m%05d|\033 [1;32m%s%s|\033 [1;34m%05d\033 [0m|\t " ,
209- 				l ,
210- 				ternary (t & syscall .NLA_F_NESTED  !=  0 , "N" , "-" ),
211- 				ternary (t & syscall .NLA_F_NET_BYTEORDER  !=  0 , "B" , "-" ),
212- 				t & attrTypeMask )
213- 			fmt .Fprintf (fd , "|len |flags| type|\n " )
214- 		} else  {
215- 			fmt .Fprintf (fd , "|%05d|%s%s|%05d|\t " ,
216- 				l ,
217- 				ternary (t & syscall .NLA_F_NESTED  !=  0 , "N" , "-" ),
218- 				ternary (t & syscall .NLA_F_NET_BYTEORDER  !=  0 , "B" , "-" ),
219- 				t & attrTypeMask )
220- 			fmt .Fprintf (fd , "|len |flags| type|\n " )
221- 		}
222- 
223- 		nextAttr  :=  i  +  nlaAlign (l )
224- 
225- 		// advance the pointer to the bytes after the header 
226- 		i  +=  nlaHeaderLen 
227- 
228- 		// Ignore zero-length attributes. 
229- 		if  l  ==  0  {
230- 			continue 
231- 		}
232- 		// If nested check the next attribute 
233- 		if  t & syscall .NLA_F_NESTED  !=  0  {
234- 			continue 
235- 		}
236- 
237- 		// Print the remaining attributes bytes 
238- 		for  ; i  <  nextAttr ; i  +=  4  {
239- 			fmt .Fprintf (fd , "| %.2x %.2x %.2x %.2x  |\t " ,
240- 				0xff & data [i ], 0xff & data [i + 1 ],
241- 				0xff & data [i + 2 ], 0xff & data [i + 3 ])
242- 
243- 			fmt .Fprintf (fd , "|      data      |" )
244- 
245- 			fmt .Fprintf (fd , "\t  %s %s %s %s\n " ,
246- 				ternary (strconv .IsPrint (rune (data [i ])), string (data [i ]), " " ),
247- 				ternary (strconv .IsPrint (rune (data [i + 1 ])), string (data [i + 1 ]), " " ),
248- 				ternary (strconv .IsPrint (rune (data [i + 2 ])), string (data [i + 2 ]), " " ),
249- 				ternary (strconv .IsPrint (rune (data [i + 3 ])), string (data [i + 3 ]), " " ),
250- 			)
251- 		}
252- 	}
253- 	fmt .Fprintf (fd , "----------------\t ------------------\n " )
254- }
255- 
35+ // ternary returns iftrue if cond is true, else iffalse. 
25636func  ternary (cond  bool , iftrue  string , iffalse  string ) string  {
25737	if  cond  {
25838		return  iftrue 
259- 	} else  {
260- 		return  iffalse 
26139	}
40+ 	return  iffalse 
26241}
0 commit comments