1 /*
2 * lib/route/link/ipvlan.c IPVLAN 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 Cong Wang <cwang@twopensource.com>
10 */
11
12 /**
13 * @ingroup link
14 * @defgroup ipvlan IPVLAN
15 * IP-based Virtual LAN link module
16 *
17 * @details
18 * \b Link Type Name: "ipvlan"
19 *
20 * @route_doc{link_ipvlan, IPVLAN Documentation}
21 *
22 * @{
23 */
24
25 #include <netlink-private/netlink.h>
26 #include <netlink/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/utils.h>
29 #include <netlink/object.h>
30 #include <netlink/route/rtnl.h>
31 #include <netlink-private/route/link/api.h>
32 #include <netlink/route/link/ipvlan.h>
33
34 #include <linux/if_link.h>
35
36 /** @cond SKIP */
37 #define IPVLAN_HAS_MODE (1<<0)
38
39 struct ipvlan_info
40 {
41 uint16_t ipi_mode;
42 uint32_t ipi_mask;
43 };
44
45 /** @endcond */
46
47 static struct nla_policy ipvlan_policy[IFLA_IPVLAN_MAX+1] = {
48 [IFLA_IPVLAN_MODE] = { .type = NLA_U16 },
49 };
50
ipvlan_alloc(struct rtnl_link * link)51 static int ipvlan_alloc(struct rtnl_link *link)
52 {
53 struct ipvlan_info *ipi;
54
55 if (link->l_info)
56 memset(link->l_info, 0, sizeof(*ipi));
57 else {
58 if ((ipi = calloc(1, sizeof(*ipi))) == NULL)
59 return -NLE_NOMEM;
60
61 link->l_info = ipi;
62 }
63
64 return 0;
65 }
66
ipvlan_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)67 static int ipvlan_parse(struct rtnl_link *link, struct nlattr *data,
68 struct nlattr *xstats)
69 {
70 struct nlattr *tb[IFLA_IPVLAN_MAX+1];
71 struct ipvlan_info *ipi;
72 int err;
73
74 NL_DBG(3, "Parsing IPVLAN link info\n");
75
76 if ((err = nla_parse_nested(tb, IFLA_IPVLAN_MAX, data, ipvlan_policy)) < 0)
77 goto errout;
78
79 if ((err = ipvlan_alloc(link)) < 0)
80 goto errout;
81
82 ipi = link->l_info;
83
84 if (tb[IFLA_IPVLAN_MODE]) {
85 ipi->ipi_mode = nla_get_u16(tb[IFLA_IPVLAN_MODE]);
86 ipi->ipi_mask |= IPVLAN_HAS_MODE;
87 }
88
89 err = 0;
90 errout:
91 return err;
92 }
93
ipvlan_free(struct rtnl_link * link)94 static void ipvlan_free(struct rtnl_link *link)
95 {
96 free(link->l_info);
97 link->l_info = NULL;
98 }
99
ipvlan_dump(struct rtnl_link * link,struct nl_dump_params * p)100 static void ipvlan_dump(struct rtnl_link *link, struct nl_dump_params *p)
101 {
102 char buf[64];
103 struct ipvlan_info *ipi = link->l_info;
104
105 if (ipi->ipi_mask & IPVLAN_HAS_MODE) {
106 rtnl_link_ipvlan_mode2str(ipi->ipi_mode, buf, sizeof(buf));
107 nl_dump(p, "ipvlan-mode %s", buf);
108 }
109 }
110
ipvlan_clone(struct rtnl_link * dst,struct rtnl_link * src)111 static int ipvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
112 {
113 struct ipvlan_info *vdst, *vsrc = src->l_info;
114 int err;
115
116 dst->l_info = NULL;
117 if ((err = rtnl_link_set_type(dst, "ipvlan")) < 0)
118 return err;
119 vdst = dst->l_info;
120
121 if (!vdst || !vsrc)
122 return -NLE_NOMEM;
123
124 memcpy(vdst, vsrc, sizeof(struct ipvlan_info));
125
126 return 0;
127 }
128
ipvlan_put_attrs(struct nl_msg * msg,struct rtnl_link * link)129 static int ipvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
130 {
131 struct ipvlan_info *ipi = link->l_info;
132 struct nlattr *data;
133
134 if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
135 return -NLE_MSGSIZE;
136
137 if (ipi->ipi_mask & IPVLAN_HAS_MODE)
138 NLA_PUT_U16(msg, IFLA_IPVLAN_MODE, ipi->ipi_mode);
139
140 nla_nest_end(msg, data);
141
142 nla_put_failure:
143
144 return 0;
145 }
146
147 static struct rtnl_link_info_ops ipvlan_info_ops = {
148 .io_name = "ipvlan",
149 .io_alloc = ipvlan_alloc,
150 .io_parse = ipvlan_parse,
151 .io_dump = {
152 [NL_DUMP_LINE] = ipvlan_dump,
153 [NL_DUMP_DETAILS] = ipvlan_dump,
154 },
155 .io_clone = ipvlan_clone,
156 .io_put_attrs = ipvlan_put_attrs,
157 .io_free = ipvlan_free,
158 };
159
160 /** @cond SKIP */
161 #define IS_IPVLAN_LINK_ASSERT(link) \
162 if ((link)->l_info_ops != &ipvlan_info_ops) { \
163 APPBUG("Link is not a ipvlan link. set type \"ipvlan\" first."); \
164 return -NLE_OPNOTSUPP; \
165 }
166 /** @endcond */
167
168 /**
169 * @name IPVLAN Object
170 * @{
171 */
172
173 /**
174 * Allocate link object of type IPVLAN
175 *
176 * @return Allocated link object or NULL.
177 */
rtnl_link_ipvlan_alloc(void)178 struct rtnl_link *rtnl_link_ipvlan_alloc(void)
179 {
180 struct rtnl_link *link;
181 int err;
182
183 if (!(link = rtnl_link_alloc()))
184 return NULL;
185
186 if ((err = rtnl_link_set_type(link, "ipvlan")) < 0) {
187 rtnl_link_put(link);
188 return NULL;
189 }
190
191 return link;
192 }
193
194 /**
195 * Check if link is a IPVLAN link
196 * @arg link Link object
197 *
198 * @return True if link is a IPVLAN link, otherwise false is returned.
199 */
rtnl_link_is_ipvlan(struct rtnl_link * link)200 int rtnl_link_is_ipvlan(struct rtnl_link *link)
201 {
202 return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ipvlan");
203 }
204
205 /**
206 * Set IPVLAN MODE
207 * @arg link Link object
208 * @arg mode IPVLAN mode
209 *
210 * @return 0 on success or a negative error code
211 */
rtnl_link_ipvlan_set_mode(struct rtnl_link * link,uint16_t mode)212 int rtnl_link_ipvlan_set_mode(struct rtnl_link *link, uint16_t mode)
213 {
214 struct ipvlan_info *ipi = link->l_info;
215
216 IS_IPVLAN_LINK_ASSERT(link);
217
218 ipi->ipi_mode = mode;
219 ipi->ipi_mask |= IPVLAN_HAS_MODE;
220
221 return 0;
222 }
223
224 /**
225 * Get IPVLAN Mode
226 * @arg link Link object
227 * @arg out_mode on success, return the mode
228 *
229 * @return 0 on success or a negative error code.
230 */
rtnl_link_ipvlan_get_mode(struct rtnl_link * link,uint16_t * out_mode)231 int rtnl_link_ipvlan_get_mode(struct rtnl_link *link, uint16_t *out_mode)
232 {
233 struct ipvlan_info *ipi = link->l_info;
234
235 IS_IPVLAN_LINK_ASSERT(link);
236
237 if (!(ipi->ipi_mask & IPVLAN_HAS_MODE))
238 return -NLE_INVAL;
239 *out_mode = ipi->ipi_mode;
240 return 0;
241 }
242
243 /** @} */
244
245 static const struct trans_tbl ipvlan_modes[] = {
246 __ADD(IPVLAN_MODE_L2, l2),
247 __ADD(IPVLAN_MODE_L3, l3),
248 };
249
250 /**
251 * @name Mode Translation
252 * @{
253 */
254
rtnl_link_ipvlan_mode2str(int mode,char * buf,size_t len)255 char *rtnl_link_ipvlan_mode2str(int mode, char *buf, size_t len)
256 {
257 return __type2str(mode, buf, len, ipvlan_modes, ARRAY_SIZE(ipvlan_modes));
258 }
259
rtnl_link_ipvlan_str2mode(const char * name)260 int rtnl_link_ipvlan_str2mode(const char *name)
261 {
262 return __str2type(name, ipvlan_modes, ARRAY_SIZE(ipvlan_modes));
263 }
264
265 /** @} */
266
ipvlan_init(void)267 static void __init ipvlan_init(void)
268 {
269 rtnl_link_register_info(&ipvlan_info_ops);
270 }
271
ipvlan_exit(void)272 static void __exit ipvlan_exit(void)
273 {
274 rtnl_link_unregister_info(&ipvlan_info_ops);
275 }
276
277 /** @} */
278