netlink_gre.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /* NHRP netlink/GRE tunnel configuration code
  2. * Copyright (c) 2014-2016 Timo Teräs
  3. *
  4. * This file is free software: you may copy, redistribute and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <netinet/in.h>
  10. #include <linux/netlink.h>
  11. #include <linux/rtnetlink.h>
  12. #include <linux/if.h>
  13. #include <linux/ip.h>
  14. #include <linux/ipv6.h>
  15. #include <linux/if_tunnel.h>
  16. #include "debug.h"
  17. #include "netlink.h"
  18. #include "znl.h"
  19. static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data, int ifindex)
  20. {
  21. struct nlmsghdr *n;
  22. struct ifinfomsg *ifi;
  23. struct zbuf payload, rtapayload;
  24. struct rtattr *rta;
  25. debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex);
  26. n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST);
  27. ifi = znl_push(zb, sizeof(*ifi));
  28. *ifi = (struct ifinfomsg) {
  29. .ifi_index = ifindex,
  30. };
  31. znl_nlmsg_complete(zb, n);
  32. if (zbuf_send(zb, netlink_req_fd) < 0 ||
  33. zbuf_recv(zb, netlink_req_fd) < 0)
  34. return -1;
  35. n = znl_nlmsg_pull(zb, &payload);
  36. if (!n) return -1;
  37. if (n->nlmsg_type != RTM_NEWLINK)
  38. return -1;
  39. ifi = znl_pull(&payload, sizeof(struct ifinfomsg));
  40. if (!ifi)
  41. return -1;
  42. debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u",
  43. ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags);
  44. if (ifi->ifi_index != ifindex)
  45. return -1;
  46. while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
  47. if (rta->rta_type == IFLA_LINKINFO)
  48. break;
  49. if (!rta) return -1;
  50. payload = rtapayload;
  51. while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
  52. if (rta->rta_type == IFLA_INFO_DATA)
  53. break;
  54. if (!rta) return -1;
  55. *data = rtapayload;
  56. return 0;
  57. }
  58. void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, unsigned int *link_index, struct in_addr *saddr)
  59. {
  60. struct zbuf *zb = zbuf_alloc(8192), data, rtapl;
  61. struct rtattr *rta;
  62. *link_index = 0;
  63. *gre_key = 0;
  64. saddr->s_addr = 0;
  65. if (__netlink_gre_get_data(zb, &data, ifindex) < 0)
  66. goto err;
  67. while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
  68. switch (rta->rta_type) {
  69. case IFLA_GRE_LINK:
  70. *link_index = zbuf_get32(&rtapl);
  71. break;
  72. case IFLA_GRE_IKEY:
  73. case IFLA_GRE_OKEY:
  74. *gre_key = zbuf_get32(&rtapl);
  75. break;
  76. case IFLA_GRE_LOCAL:
  77. saddr->s_addr = zbuf_get32(&rtapl);
  78. break;
  79. }
  80. }
  81. err:
  82. zbuf_free(zb);
  83. }
  84. void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index)
  85. {
  86. struct nlmsghdr *n;
  87. struct ifinfomsg *ifi;
  88. struct rtattr *rta_info, *rta_data, *rta;
  89. struct zbuf *zr = zbuf_alloc(8192), data, rtapl;
  90. struct zbuf *zb = zbuf_alloc(8192);
  91. size_t len;
  92. if (__netlink_gre_get_data(zr, &data, ifindex) < 0)
  93. goto err;
  94. n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST);
  95. ifi = znl_push(zb, sizeof(*ifi));
  96. *ifi = (struct ifinfomsg) {
  97. .ifi_index = ifindex,
  98. };
  99. rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO);
  100. znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3);
  101. rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA);
  102. znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index);
  103. while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
  104. if (rta->rta_type == IFLA_GRE_LINK)
  105. continue;
  106. len = zbuf_used(&rtapl);
  107. znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len);
  108. }
  109. znl_rta_nested_complete(zb, rta_data);
  110. znl_rta_nested_complete(zb, rta_info);
  111. znl_nlmsg_complete(zb, n);
  112. zbuf_send(zb, netlink_req_fd);
  113. zbuf_recv(zb, netlink_req_fd);
  114. err:
  115. zbuf_free(zb);
  116. zbuf_free(zr);
  117. }