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
37 #define VRF_TABLE_ID_MAX RT_TABLE_MAX
38
39 /** @cond SKIP */
40 #define VRF_HAS_TABLE_ID (1<<0)
41
42 struct vrf_info {
43 uint32_t table_id;
44 uint32_t vi_mask;
45 };
46
47 /** @endcond */
48
49 static struct nla_policy vrf_policy[IFLA_VRF_MAX + 1] = {
50 [IFLA_VRF_TABLE] = { .type = NLA_U32 },
51 };
52
vrf_alloc(struct rtnl_link * link)53 static int vrf_alloc(struct rtnl_link *link)
54 {
55 struct vrf_info *vi;
56
57 if (link->l_info) {
58 memset(link->l_info, 0, sizeof (*vi));
59 return 0;
60 }
61
62 if ((vi = calloc(1, sizeof(*vi))) == NULL)
63 return -NLE_NOMEM;
64
65 link->l_info = vi;
66
67 return 0;
68 }
69
vrf_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)70 static int vrf_parse(struct rtnl_link *link, struct nlattr *data,
71 struct nlattr *xstats)
72 {
73 struct nlattr *tb[IFLA_VRF_MAX+1];
74 struct vrf_info *vi;
75 int err;
76
77 NL_DBG(3, "Parsing VRF link info");
78
79 if ((err = nla_parse_nested(tb, IFLA_VRF_MAX, data, vrf_policy)) < 0)
80 goto errout;
81
82 if ((err = vrf_alloc(link)) < 0)
83 goto errout;
84
85 vi = link->l_info;
86
87 if (tb[IFLA_VRF_TABLE]) {
88 vi->table_id = nla_get_u32(tb[IFLA_VRF_TABLE]);
89 vi->vi_mask |= VRF_HAS_TABLE_ID;
90 }
91
92 err = 0;
93
94 errout:
95 return err;
96 }
97
vrf_free(struct rtnl_link * link)98 static void vrf_free(struct rtnl_link *link)
99 {
100 free(link->l_info);
101 link->l_info = NULL;
102 }
103
vrf_clone(struct rtnl_link * dst,struct rtnl_link * src)104 static int vrf_clone(struct rtnl_link *dst, struct rtnl_link *src)
105 {
106 struct vrf_info *vdst, *vsrc = src->l_info;
107 int err;
108
109 dst->l_info = NULL;
110 if ((err = rtnl_link_set_type(dst, "vrf")) < 0)
111 return err;
112 vdst = dst->l_info;
113
114 BUG_ON(!vdst || !vsrc);
115
116 memcpy(vdst, vsrc, sizeof(struct vrf_info));
117
118 return 0;
119 }
120
vrf_put_attrs(struct nl_msg * msg,struct rtnl_link * link)121 static int vrf_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
122 {
123 struct vrf_info *vi = link->l_info;
124 struct nlattr *data;
125
126 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
127 return -NLE_NOMEM;
128
129 if (vi->vi_mask & VRF_HAS_TABLE_ID) {
130 NLA_PUT_U32(msg, IFLA_VRF_TABLE, vi->table_id);
131 }
132
133 nla_nest_end(msg, data);
134
135 nla_put_failure:
136
137 return 0;
138 }
139
vrf_dump(struct rtnl_link * link,struct nl_dump_params * p)140 static void vrf_dump(struct rtnl_link *link, struct nl_dump_params *p)
141 {
142 struct vrf_info *vi = link->l_info;
143
144 if (vi->vi_mask & VRF_HAS_TABLE_ID) {
145 nl_dump(p, "table-id %u", vi->table_id);
146 }
147 }
148
149 static struct rtnl_link_info_ops vrf_info_ops = {
150 .io_name = "vrf",
151 .io_alloc = vrf_alloc,
152 .io_parse = vrf_parse,
153 .io_dump = {
154 [NL_DUMP_LINE] = vrf_dump,
155 [NL_DUMP_DETAILS] = vrf_dump,
156 },
157 .io_clone = vrf_clone,
158 .io_put_attrs = vrf_put_attrs,
159 .io_free = vrf_free,
160 };
161
162 /** @cond SKIP */
163 #define IS_VRF_LINK_ASSERT(link) \
164 if ((link)->l_info_ops != &vrf_info_ops) { \
165 APPBUG("Link is not a VRF link. set type \"vrf\" first."); \
166 return -NLE_OPNOTSUPP; \
167 }
168 /** @endcond */
169
170 /**
171 * @name VRF Object
172 * @{
173 */
174
175 /**
176 * Allocate link object of type VRF
177 *
178 * @return Allocated link object or NULL.
179 */
rtnl_link_vrf_alloc(void)180 struct rtnl_link *rtnl_link_vrf_alloc(void)
181 {
182 struct rtnl_link *link;
183 int err;
184
185 if (!(link = rtnl_link_alloc()))
186 return NULL;
187
188 if ((err = rtnl_link_set_type(link, "vrf")) < 0) {
189 rtnl_link_put(link);
190 return NULL;
191 }
192
193 return link;
194 }
195
196 /**
197 * Check if link is a VRF link
198 * @arg link Link object
199 *
200 * @return True if link is a VRF link, otherwise false is returned.
201 */
rtnl_link_is_vrf(struct rtnl_link * link)202 int rtnl_link_is_vrf(struct rtnl_link *link)
203 {
204 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vrf");
205 }
206
207 /**
208 * Get VRF table id
209 * @arg link Link object
210 * @arg id Pointer to store table identifier
211 *
212 * @return 0 on success or a negative error code
213 */
rtnl_link_vrf_get_tableid(struct rtnl_link * link,uint32_t * id)214 int rtnl_link_vrf_get_tableid(struct rtnl_link *link, uint32_t *id)
215 {
216 struct vrf_info *vi = link->l_info;
217
218 IS_VRF_LINK_ASSERT(link);
219 if(!id)
220 return -NLE_INVAL;
221
222 if (vi->vi_mask & VRF_HAS_TABLE_ID)
223 *id = vi->table_id;
224 else
225 return -NLE_AGAIN;
226
227 return 0;
228 }
229
230 /**
231 * Set VRF table id
232 * @arg link Link object
233 * @arg id Table identifier associated with VRF link
234 *
235 * @return 0 on success or a negative error code
236 */
rtnl_link_vrf_set_tableid(struct rtnl_link * link,uint32_t id)237 int rtnl_link_vrf_set_tableid(struct rtnl_link *link, uint32_t id)
238 {
239 struct vrf_info *vi = link->l_info;
240
241 IS_VRF_LINK_ASSERT(link);
242 if(id > VRF_TABLE_ID_MAX)
243 return -NLE_INVAL;
244
245 vi->table_id = id;
246 vi->vi_mask |= VRF_HAS_TABLE_ID;
247
248 return 0;
249 }
250
251 /** @} */
252
vrf_init(void)253 static void __init vrf_init(void)
254 {
255 rtnl_link_register_info(&vrf_info_ops);
256 }
257
vrf_exit(void)258 static void __exit vrf_exit(void)
259 {
260 rtnl_link_unregister_info(&vrf_info_ops);
261 }
262
263 /** @} */
264