• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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