macvlan.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * lib/route/link/macvlan.c MACVLAN 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) 2013 Michael Braun <michael-dev@fami-braun.de>
  10. */
  11. /**
  12. * @ingroup link
  13. * @defgroup macvlan MACVLAN
  14. * MAC-based Virtual LAN link module
  15. *
  16. * @details
  17. * \b Link Type Name: "macvlan"
  18. *
  19. * @route_doc{link_macvlan, MACVLAN Documentation}
  20. *
  21. * @{
  22. */
  23. #include <netlink-private/netlink.h>
  24. #include <netlink/netlink.h>
  25. #include <netlink/attr.h>
  26. #include <netlink/utils.h>
  27. #include <netlink/object.h>
  28. #include <netlink/route/rtnl.h>
  29. #include <netlink-private/route/link/api.h>
  30. #include <netlink/route/link/macvlan.h>
  31. #include <linux/if_link.h>
  32. /** @cond SKIP */
  33. #define MACVLAN_HAS_MODE (1<<0)
  34. #define MACVLAN_HAS_FLAGS (1<<1)
  35. struct macvlan_info
  36. {
  37. uint32_t mvi_mode;
  38. uint16_t mvi_flags; // there currently is only one flag and kernel has no flags_mask yet
  39. uint32_t mvi_mask;
  40. };
  41. /** @endcond */
  42. static struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX+1] = {
  43. [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
  44. [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
  45. };
  46. static int macvlan_alloc(struct rtnl_link *link)
  47. {
  48. struct macvlan_info *mvi;
  49. if ((mvi = calloc(1, sizeof(*mvi))) == NULL)
  50. return -NLE_NOMEM;
  51. link->l_info = mvi;
  52. return 0;
  53. }
  54. static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
  55. struct nlattr *xstats)
  56. {
  57. struct nlattr *tb[IFLA_MACVLAN_MAX+1];
  58. struct macvlan_info *mvi;
  59. int err;
  60. NL_DBG(3, "Parsing MACVLAN link info");
  61. if ((err = nla_parse_nested(tb, IFLA_MACVLAN_MAX, data, macvlan_policy)) < 0)
  62. goto errout;
  63. if ((err = macvlan_alloc(link)) < 0)
  64. goto errout;
  65. mvi = link->l_info;
  66. if (tb[IFLA_MACVLAN_MODE]) {
  67. mvi->mvi_mode = nla_get_u32(tb[IFLA_MACVLAN_MODE]);
  68. mvi->mvi_mask |= MACVLAN_HAS_MODE;
  69. }
  70. if (tb[IFLA_MACVLAN_FLAGS]) {
  71. mvi->mvi_mode = nla_get_u16(tb[IFLA_MACVLAN_FLAGS]);
  72. mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
  73. }
  74. err = 0;
  75. errout:
  76. return err;
  77. }
  78. static void macvlan_free(struct rtnl_link *link)
  79. {
  80. free(link->l_info);
  81. link->l_info = NULL;
  82. }
  83. static void macvlan_dump(struct rtnl_link *link, struct nl_dump_params *p)
  84. {
  85. char buf[64];
  86. struct macvlan_info *mvi = link->l_info;
  87. if (mvi->mvi_mask & MACVLAN_HAS_MODE) {
  88. rtnl_link_macvlan_mode2str(mvi->mvi_mode, buf, sizeof(buf));
  89. nl_dump(p, "macvlan-mode %s", buf);
  90. }
  91. if (mvi->mvi_mask & MACVLAN_HAS_FLAGS) {
  92. rtnl_link_macvlan_flags2str(mvi->mvi_flags, buf, sizeof(buf));
  93. nl_dump(p, "macvlan-flags %s", buf);
  94. }
  95. }
  96. static int macvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
  97. {
  98. struct macvlan_info *vdst, *vsrc = src->l_info;
  99. int err;
  100. dst->l_info = NULL;
  101. if ((err = rtnl_link_set_type(dst, "macvlan")) < 0)
  102. return err;
  103. vdst = dst->l_info;
  104. if (!vdst || !vsrc)
  105. return -NLE_NOMEM;
  106. memcpy(vdst, vsrc, sizeof(struct macvlan_info));
  107. return 0;
  108. }
  109. static int macvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
  110. {
  111. struct macvlan_info *mvi = link->l_info;
  112. struct nlattr *data;
  113. if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
  114. return -NLE_MSGSIZE;
  115. if (mvi->mvi_mask & MACVLAN_HAS_MODE)
  116. NLA_PUT_U32(msg, IFLA_MACVLAN_MODE, mvi->mvi_mode);
  117. if (mvi->mvi_mask & MACVLAN_HAS_FLAGS)
  118. NLA_PUT_U16(msg, IFLA_MACVLAN_FLAGS, mvi->mvi_flags);
  119. nla_nest_end(msg, data);
  120. nla_put_failure:
  121. return 0;
  122. }
  123. static struct rtnl_link_info_ops macvlan_info_ops = {
  124. .io_name = "macvlan",
  125. .io_alloc = macvlan_alloc,
  126. .io_parse = macvlan_parse,
  127. .io_dump = {
  128. [NL_DUMP_LINE] = macvlan_dump,
  129. [NL_DUMP_DETAILS] = macvlan_dump,
  130. },
  131. .io_clone = macvlan_clone,
  132. .io_put_attrs = macvlan_put_attrs,
  133. .io_free = macvlan_free,
  134. };
  135. /** @cond SKIP */
  136. #define IS_MACVLAN_LINK_ASSERT(link) \
  137. if ((link)->l_info_ops != &macvlan_info_ops) { \
  138. APPBUG("Link is not a macvlan link. set type \"macvlan\" first."); \
  139. return -NLE_OPNOTSUPP; \
  140. }
  141. /** @endcond */
  142. /**
  143. * @name MACVLAN Object
  144. * @{
  145. */
  146. /**
  147. * Allocate link object of type MACVLAN
  148. *
  149. * @return Allocated link object or NULL.
  150. */
  151. struct rtnl_link *rtnl_link_macvlan_alloc(void)
  152. {
  153. struct rtnl_link *link;
  154. int err;
  155. if (!(link = rtnl_link_alloc()))
  156. return NULL;
  157. if ((err = rtnl_link_set_type(link, "macvlan")) < 0) {
  158. rtnl_link_put(link);
  159. return NULL;
  160. }
  161. return link;
  162. }
  163. /**
  164. * Check if link is a MACVLAN link
  165. * @arg link Link object
  166. *
  167. * @return True if link is a MACVLAN link, otherwise false is returned.
  168. */
  169. int rtnl_link_is_macvlan(struct rtnl_link *link)
  170. {
  171. return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvlan");
  172. }
  173. /**
  174. * Set MACVLAN MODE
  175. * @arg link Link object
  176. * @arg mode MACVLAN mode
  177. *
  178. * @return 0 on success or a negative error code
  179. */
  180. int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
  181. {
  182. struct macvlan_info *mvi = link->l_info;
  183. IS_MACVLAN_LINK_ASSERT(link);
  184. mvi->mvi_mode = mode;
  185. mvi->mvi_mask |= MACVLAN_HAS_MODE;
  186. return 0;
  187. }
  188. /**
  189. * Get MACVLAN Mode
  190. * @arg link Link object
  191. *
  192. * @return MACVLAN mode, 0 if not set or a negative error code.
  193. */
  194. uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *link)
  195. {
  196. struct macvlan_info *mvi = link->l_info;
  197. IS_MACVLAN_LINK_ASSERT(link);
  198. if (mvi->mvi_mask & MACVLAN_HAS_MODE)
  199. return mvi->mvi_mode;
  200. else
  201. return 0;
  202. }
  203. /**
  204. * Set MACVLAN flags
  205. * @arg link Link object
  206. * @arg flags MACVLAN flags
  207. *
  208. * @return 0 on success or a negative error code.
  209. */
  210. int rtnl_link_macvlan_set_flags(struct rtnl_link *link, uint16_t flags)
  211. {
  212. struct macvlan_info *mvi = link->l_info;
  213. IS_MACVLAN_LINK_ASSERT(link);
  214. mvi->mvi_flags |= flags;
  215. mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
  216. return 0;
  217. }
  218. /**
  219. * Unset MACVLAN flags
  220. * @arg link Link object
  221. * @arg flags MACVLAN flags
  222. *
  223. * Note: kernel currently only has a single flag and lacks flags_mask to
  224. * indicate which flags shall be changed (it always all).
  225. *
  226. * @return 0 on success or a negative error code.
  227. */
  228. int rtnl_link_macvlan_unset_flags(struct rtnl_link *link, uint16_t flags)
  229. {
  230. struct macvlan_info *mvi = link->l_info;
  231. IS_MACVLAN_LINK_ASSERT(link);
  232. mvi->mvi_flags &= ~flags;
  233. mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
  234. return 0;
  235. }
  236. /**
  237. * Get MACVLAN flags
  238. * @arg link Link object
  239. *
  240. * @return MACVLAN flags, 0 if none set, or a negative error code.
  241. */
  242. uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *link)
  243. {
  244. struct macvlan_info *mvi = link->l_info;
  245. IS_MACVLAN_LINK_ASSERT(link);
  246. return mvi->mvi_flags;
  247. }
  248. /** @} */
  249. static const struct trans_tbl macvlan_flags[] = {
  250. __ADD(MACVLAN_FLAG_NOPROMISC, nopromisc)
  251. };
  252. static const struct trans_tbl macvlan_modes[] = {
  253. __ADD(MACVLAN_MODE_PRIVATE, private)
  254. __ADD(MACVLAN_MODE_VEPA, vepa)
  255. __ADD(MACVLAN_MODE_BRIDGE, bridge)
  256. __ADD(MACVLAN_MODE_PASSTHRU, passthru)
  257. };
  258. /**
  259. * @name Flag Translation
  260. * @{
  261. */
  262. char *rtnl_link_macvlan_flags2str(int flags, char *buf, size_t len)
  263. {
  264. return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
  265. }
  266. int rtnl_link_macvlan_str2flags(const char *name)
  267. {
  268. return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
  269. }
  270. /** @} */
  271. /**
  272. * @name Mode Translation
  273. * @{
  274. */
  275. char *rtnl_link_macvlan_mode2str(int mode, char *buf, size_t len)
  276. {
  277. return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
  278. }
  279. int rtnl_link_macvlan_str2mode(const char *name)
  280. {
  281. return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
  282. }
  283. /** @} */
  284. static void __init macvlan_init(void)
  285. {
  286. rtnl_link_register_info(&macvlan_info_ops);
  287. }
  288. static void __exit macvlan_exit(void)
  289. {
  290. rtnl_link_unregister_info(&macvlan_info_ops);
  291. }
  292. /** @} */