1 /*
2 * lib/route/link/vrf.c VRF Link Info
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
7 * of the License.
8 *
9 * Copyright (c) 2015 Cumulus Networks. All rights reserved.
10 * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
11 */
12
13 /**
14 * @ingroup link
15 * @defgroup vrf VRF
16 * Virtual Routing and Forwarding link module
17 *
18 * @details
19 * \b Link Type Name: "vrf"
20 *
21 * @route_doc{link_vrf, VRF Documentation}
22 *
23 * @{
24 */
25
26 #include <netlink-private/netlink.h>
27 #include <netlink/netlink.h>
28 #include <netlink/attr.h>
29 #include <netlink/utils.h>
30 #include <netlink/object.h>
31 #include <netlink/route/rtnl.h>
32 #include <netlink-private/route/link/api.h>
33 #include <netlink/route/link/vrf.h>
34
35 #include <linux/if_link.h>
36 #include <linux-private/linux/rtnetlink.h>
37
38 #define VRF_TABLE_ID_MAX RT_TABLE_MAX
39
40 /** @cond SKIP */
41 #define VRF_HAS_TABLE_ID (1<<0)
42
43 struct vrf_info {
44 uint32_t table_id;
45 uint32_t vi_mask;
46 };
47
48 /** @endcond */
49
50 static struct nla_policy vrf_policy[IFLA_VRF_MAX + 1] = {
51 [IFLA_VRF_TABLE] = { .type = NLA_U32 },
52 };
53
vrf_alloc(struct rtnl_link * link)54 static int vrf_alloc(struct rtnl_link *link)
55 {
56 struct vrf_info *vi;
57
58 if (link->l_info) {
59 memset(link->l_info, 0, sizeof (*vi));
60 return 0;
61 }
62
63 if ((vi = calloc(1, sizeof(*vi))) == NULL)
64 return -NLE_NOMEM;
65
66 link->l_info = vi;
67
68 return 0;
69 }
70
vrf_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)71 static int vrf_parse(struct rtnl_link *link, struct nlattr *data,
72 struct nlattr *xstats)
73 {
74 struct nlattr *tb[IFLA_VRF_MAX+1];
75 struct vrf_info *vi;
76 int err;
77
78 NL_DBG(3, "Parsing VRF link info");
79
80 if ((err = nla_parse_nested(tb, IFLA_VRF_MAX, data, vrf_policy)) < 0)
81 goto errout;
82
83 if ((err = vrf_alloc(link)) < 0)
84 goto errout;
85
86 vi = link->l_info;
87
88 if (tb[IFLA_VRF_TABLE]) {
89 vi->table_id = nla_get_u32(tb[IFLA_VRF_TABLE]);
90 vi->vi_mask |= VRF_HAS_TABLE_ID;
91 }
92
93 err = 0;
94
95 errout:
96 return err;
97 }
98
vrf_free(struct rtnl_link * link)99 static void vrf_free(struct rtnl_link *link)
100 {
101 free(link->l_info);
102 link->l_info = NULL;
103 }
104
vrf_clone(struct rtnl_link * dst,struct rtnl_link * src)105 static int vrf_clone(struct rtnl_link *dst, struct rtnl_link *src)
106 {
107 struct vrf_info *vdst, *vsrc = src->l_info;
108 int err;
109
110 dst->l_info = NULL;
111 if ((err = rtnl_link_set_type(dst, "vrf")) < 0)
112 return err;
113 vdst = dst->l_info;
114
115 BUG_ON(!vdst || !vsrc);
116
117 memcpy(vdst, vsrc, sizeof(struct vrf_info));
118
119 return 0;
120 }
121
vrf_put_attrs(struct nl_msg * msg,struct rtnl_link * link)122 static int vrf_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
123 {
124 struct vrf_info *vi = link->l_info;
125 struct nlattr *data;
126
127 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
128 return -NLE_NOMEM;
129
130 if (vi->vi_mask & VRF_HAS_TABLE_ID) {
131 NLA_PUT_U32(msg, IFLA_VRF_TABLE, vi->table_id);
132 }
133
134 nla_nest_end(msg, data);
135
136 nla_put_failure:
137
138 return 0;
139 }
140
vrf_dump(struct rtnl_link * link,struct nl_dump_params * p)141 static void vrf_dump(struct rtnl_link *link, struct nl_dump_params *p)
142 {
143 struct vrf_info *vi = link->l_info;
144
145 if (vi->vi_mask & VRF_HAS_TABLE_ID) {
146 nl_dump(p, "table-id %u", vi->table_id);
147 }
148 }
149
150 static struct rtnl_link_info_ops vrf_info_ops = {
151 .io_name = "vrf",
152 .io_alloc = vrf_alloc,
153 .io_parse = vrf_parse,
154 .io_dump = {
155 [NL_DUMP_LINE] = vrf_dump,
156 [NL_DUMP_DETAILS] = vrf_dump,
157 },
158 .io_clone = vrf_clone,
159 .io_put_attrs = vrf_put_attrs,
160 .io_free = vrf_free,
161 };
162
163 /** @cond SKIP */
164 #define IS_VRF_LINK_ASSERT(link) \
165 if ((link)->l_info_ops != &vrf_info_ops) { \
166 APPBUG("Link is not a VRF link. set type \"vrf\" first."); \
167 return -NLE_OPNOTSUPP; \
168 }
169 /** @endcond */
170
171 /**
172 * @name VRF Object
173 * @{
174 */
175
176 /**
177 * Allocate link object of type VRF
178 *
179 * @return Allocated link object or NULL.
180 */
rtnl_link_vrf_alloc(void)181 struct rtnl_link *rtnl_link_vrf_alloc(void)
182 {
183 struct rtnl_link *link;
184 int err;
185
186 if (!(link = rtnl_link_alloc()))
187 return NULL;
188
189 if ((err = rtnl_link_set_type(link, "vrf")) < 0) {
190 rtnl_link_put(link);
191 return NULL;
192 }
193
194 return link;
195 }
196
197 /**
198 * Check if link is a VRF link
199 * @arg link Link object
200 *
201 * @return True if link is a VRF link, otherwise false is returned.
202 */
rtnl_link_is_vrf(struct rtnl_link * link)203 int rtnl_link_is_vrf(struct rtnl_link *link)
204 {
205 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vrf");
206 }
207
208 /**
209 * Get VRF table id
210 * @arg link Link object
211 * @arg id Pointer to store table identifier
212 *
213 * @return 0 on success or a negative error code
214 */
rtnl_link_vrf_get_tableid(struct rtnl_link * link,uint32_t * id)215 int rtnl_link_vrf_get_tableid(struct rtnl_link *link, uint32_t *id)
216 {
217 struct vrf_info *vi = link->l_info;
218
219 IS_VRF_LINK_ASSERT(link);
220 if(!id)
221 return -NLE_INVAL;
222
223 if (vi->vi_mask & VRF_HAS_TABLE_ID)
224 *id = vi->table_id;
225 else
226 return -NLE_AGAIN;
227
228 return 0;
229 }
230
231 /**
232 * Set VRF table id
233 * @arg link Link object
234 * @arg id Table identifier associated with VRF link
235 *
236 * @return 0 on success or a negative error code
237 */
rtnl_link_vrf_set_tableid(struct rtnl_link * link,uint32_t id)238 int rtnl_link_vrf_set_tableid(struct rtnl_link *link, uint32_t id)
239 {
240 struct vrf_info *vi = link->l_info;
241
242 IS_VRF_LINK_ASSERT(link);
243 if(id > VRF_TABLE_ID_MAX)
244 return -NLE_INVAL;
245
246 vi->table_id = id;
247 vi->vi_mask |= VRF_HAS_TABLE_ID;
248
249 return 0;
250 }
251
252 /** @} */
253
vrf_init(void)254 static void __init vrf_init(void)
255 {
256 rtnl_link_register_info(&vrf_info_ops);
257 }
258
vrf_exit(void)259 static void __exit vrf_exit(void)
260 {
261 rtnl_link_unregister_info(&vrf_info_ops);
262 }
263
264 /** @} */
265