Skip to content

Commit 4b132aa

Browse files
committed
tools: Add xdrgen
Add a Python-based tool for translating XDR specifications into XDR encoder and decoder functions written in the Linux kernel's C coding style. The generator attempts to match the usual C coding style of the Linux kernel's SunRPC consumers. This approach is similar to the netlink code generator in tools/net/ynl . The maintainability benefits of machine-generated XDR code include: - Stronger type checking - Reduces the number of bugs introduced by human error - Makes the XDR code easier to audit and analyze - Enables rapid prototyping of new RPC-based protocols - Hardens the layering between protocol logic and marshaling - Makes it easier to add observability on demand - Unit tests might be built for both the tool and (automatically) for the generated code In addition, converting the XDR layer to use memory-safe languages such as Rust will be easier if much of the code can be converted automatically. Tested-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent 45bb63e commit 4b132aa

File tree

153 files changed

+4196
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

153 files changed

+4196
-0
lines changed
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (c) 2024 Oracle and/or its affiliates.
4+
*
5+
* This header defines XDR data type primitives specified in
6+
* Section 4 of RFC 4506, used by RPC programs implemented
7+
* in the Linux kernel.
8+
*/
9+
10+
#ifndef _SUNRPC_XDRGEN__BUILTINS_H_
11+
#define _SUNRPC_XDRGEN__BUILTINS_H_
12+
13+
#include <linux/sunrpc/xdr.h>
14+
15+
static inline bool
16+
xdrgen_decode_void(struct xdr_stream *xdr)
17+
{
18+
return true;
19+
}
20+
21+
static inline bool
22+
xdrgen_encode_void(struct xdr_stream *xdr)
23+
{
24+
return true;
25+
}
26+
27+
static inline bool
28+
xdrgen_decode_bool(struct xdr_stream *xdr, bool *ptr)
29+
{
30+
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
31+
32+
if (unlikely(!p))
33+
return false;
34+
*ptr = (*p != xdr_zero);
35+
return true;
36+
}
37+
38+
static inline bool
39+
xdrgen_encode_bool(struct xdr_stream *xdr, bool val)
40+
{
41+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
42+
43+
if (unlikely(!p))
44+
return false;
45+
*p = val ? xdr_one : xdr_zero;
46+
return true;
47+
}
48+
49+
static inline bool
50+
xdrgen_decode_int(struct xdr_stream *xdr, s32 *ptr)
51+
{
52+
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
53+
54+
if (unlikely(!p))
55+
return false;
56+
*ptr = be32_to_cpup(p);
57+
return true;
58+
}
59+
60+
static inline bool
61+
xdrgen_encode_int(struct xdr_stream *xdr, s32 val)
62+
{
63+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
64+
65+
if (unlikely(!p))
66+
return false;
67+
*p = cpu_to_be32(val);
68+
return true;
69+
}
70+
71+
static inline bool
72+
xdrgen_decode_unsigned_int(struct xdr_stream *xdr, u32 *ptr)
73+
{
74+
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
75+
76+
if (unlikely(!p))
77+
return false;
78+
*ptr = be32_to_cpup(p);
79+
return true;
80+
}
81+
82+
static inline bool
83+
xdrgen_encode_unsigned_int(struct xdr_stream *xdr, u32 val)
84+
{
85+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
86+
87+
if (unlikely(!p))
88+
return false;
89+
*p = cpu_to_be32(val);
90+
return true;
91+
}
92+
93+
static inline bool
94+
xdrgen_decode_long(struct xdr_stream *xdr, s32 *ptr)
95+
{
96+
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
97+
98+
if (unlikely(!p))
99+
return false;
100+
*ptr = be32_to_cpup(p);
101+
return true;
102+
}
103+
104+
static inline bool
105+
xdrgen_encode_long(struct xdr_stream *xdr, s32 val)
106+
{
107+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
108+
109+
if (unlikely(!p))
110+
return false;
111+
*p = cpu_to_be32(val);
112+
return true;
113+
}
114+
115+
static inline bool
116+
xdrgen_decode_unsigned_long(struct xdr_stream *xdr, u32 *ptr)
117+
{
118+
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT);
119+
120+
if (unlikely(!p))
121+
return false;
122+
*ptr = be32_to_cpup(p);
123+
return true;
124+
}
125+
126+
static inline bool
127+
xdrgen_encode_unsigned_long(struct xdr_stream *xdr, u32 val)
128+
{
129+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT);
130+
131+
if (unlikely(!p))
132+
return false;
133+
*p = cpu_to_be32(val);
134+
return true;
135+
}
136+
137+
static inline bool
138+
xdrgen_decode_hyper(struct xdr_stream *xdr, s64 *ptr)
139+
{
140+
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT * 2);
141+
142+
if (unlikely(!p))
143+
return false;
144+
*ptr = get_unaligned_be64(p);
145+
return true;
146+
}
147+
148+
static inline bool
149+
xdrgen_encode_hyper(struct xdr_stream *xdr, s64 val)
150+
{
151+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT * 2);
152+
153+
if (unlikely(!p))
154+
return false;
155+
put_unaligned_be64(val, p);
156+
return true;
157+
}
158+
159+
static inline bool
160+
xdrgen_decode_unsigned_hyper(struct xdr_stream *xdr, u64 *ptr)
161+
{
162+
__be32 *p = xdr_inline_decode(xdr, XDR_UNIT * 2);
163+
164+
if (unlikely(!p))
165+
return false;
166+
*ptr = get_unaligned_be64(p);
167+
return true;
168+
}
169+
170+
static inline bool
171+
xdrgen_encode_unsigned_hyper(struct xdr_stream *xdr, u64 val)
172+
{
173+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT * 2);
174+
175+
if (unlikely(!p))
176+
return false;
177+
put_unaligned_be64(val, p);
178+
return true;
179+
}
180+
181+
static inline bool
182+
xdrgen_decode_string(struct xdr_stream *xdr, string *ptr, u32 maxlen)
183+
{
184+
__be32 *p;
185+
u32 len;
186+
187+
if (unlikely(xdr_stream_decode_u32(xdr, &len) != XDR_UNIT))
188+
return false;
189+
if (unlikely(maxlen && len > maxlen))
190+
return false;
191+
if (len != 0) {
192+
p = xdr_inline_decode(xdr, len);
193+
if (unlikely(!p))
194+
return false;
195+
ptr->data = (unsigned char *)p;
196+
}
197+
ptr->len = len;
198+
return true;
199+
}
200+
201+
static inline bool
202+
xdrgen_encode_string(struct xdr_stream *xdr, string val, u32 maxlen)
203+
{
204+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT + xdr_align_size(val.len));
205+
206+
if (unlikely(!p))
207+
return false;
208+
xdr_encode_opaque(p, val.data, val.len);
209+
return true;
210+
}
211+
212+
static inline bool
213+
xdrgen_decode_opaque(struct xdr_stream *xdr, opaque *ptr, u32 maxlen)
214+
{
215+
__be32 *p;
216+
u32 len;
217+
218+
if (unlikely(xdr_stream_decode_u32(xdr, &len) != XDR_UNIT))
219+
return false;
220+
if (unlikely(maxlen && len > maxlen))
221+
return false;
222+
if (len != 0) {
223+
p = xdr_inline_decode(xdr, len);
224+
if (unlikely(!p))
225+
return false;
226+
ptr->data = (u8 *)p;
227+
}
228+
ptr->len = len;
229+
return true;
230+
}
231+
232+
static inline bool
233+
xdrgen_encode_opaque(struct xdr_stream *xdr, opaque val)
234+
{
235+
__be32 *p = xdr_reserve_space(xdr, XDR_UNIT + xdr_align_size(val.len));
236+
237+
if (unlikely(!p))
238+
return false;
239+
xdr_encode_opaque(p, val.data, val.len);
240+
return true;
241+
}
242+
243+
#endif /* _SUNRPC_XDRGEN__BUILTINS_H_ */

include/linux/sunrpc/xdrgen/_defs.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (c) 2024 Oracle and/or its affiliates.
4+
*
5+
* This header defines XDR data type primitives specified in
6+
* Section 4 of RFC 4506, used by RPC programs implemented
7+
* in the Linux kernel.
8+
*/
9+
10+
#ifndef _SUNRPC_XDRGEN__DEFS_H_
11+
#define _SUNRPC_XDRGEN__DEFS_H_
12+
13+
#define TRUE (true)
14+
#define FALSE (false)
15+
16+
typedef struct {
17+
u32 len;
18+
unsigned char *data;
19+
} string;
20+
21+
typedef struct {
22+
u32 len;
23+
u8 *data;
24+
} opaque;
25+
26+
#endif /* _SUNRPC_XDRGEN__DEFS_H_ */

tools/net/sunrpc/xdrgen/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__pycache__
2+
generators/__pycache__

0 commit comments

Comments
 (0)