]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/netlink_gre.c
Merge pull request #1860 from qlyoung/debug-mt-safe
[mirror_frr.git] / nhrpd / netlink_gre.c
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
10 #include <sys/socket.h>
11 #include <linux/netlink.h>
12 #include <linux/rtnetlink.h>
13 #include <linux/in.h>
14 #include <linux/if.h>
15 #include <linux/ip.h>
16 #include <linux/ipv6.h>
17 #include <linux/if_tunnel.h>
18
19 #include "debug.h"
20 #include "netlink.h"
21 #include "znl.h"
22
23 static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data,
24 int ifindex)
25 {
26 struct nlmsghdr *n;
27 struct ifinfomsg *ifi;
28 struct zbuf payload, rtapayload;
29 struct rtattr *rta;
30
31 debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex);
32
33 n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST);
34 ifi = znl_push(zb, sizeof(*ifi));
35 *ifi = (struct ifinfomsg){
36 .ifi_index = ifindex,
37 };
38 znl_nlmsg_complete(zb, n);
39
40 if (zbuf_send(zb, netlink_req_fd) < 0
41 || zbuf_recv(zb, netlink_req_fd) < 0)
42 return -1;
43
44 n = znl_nlmsg_pull(zb, &payload);
45 if (!n)
46 return -1;
47
48 if (n->nlmsg_type != RTM_NEWLINK)
49 return -1;
50
51 ifi = znl_pull(&payload, sizeof(struct ifinfomsg));
52 if (!ifi)
53 return -1;
54
55 debugf(NHRP_DEBUG_KERNEL,
56 "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u",
57 ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags);
58
59 if (ifi->ifi_index != ifindex)
60 return -1;
61
62 while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
63 if (rta->rta_type == IFLA_LINKINFO)
64 break;
65 if (!rta)
66 return -1;
67
68 payload = rtapayload;
69 while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
70 if (rta->rta_type == IFLA_INFO_DATA)
71 break;
72 if (!rta)
73 return -1;
74
75 *data = rtapayload;
76 return 0;
77 }
78
79 void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key,
80 unsigned int *link_index, struct in_addr *saddr)
81 {
82 struct zbuf *zb = zbuf_alloc(8192), data, rtapl;
83 struct rtattr *rta;
84
85 *link_index = 0;
86 *gre_key = 0;
87 saddr->s_addr = 0;
88
89 if (__netlink_gre_get_data(zb, &data, ifindex) < 0)
90 goto err;
91
92 while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
93 switch (rta->rta_type) {
94 case IFLA_GRE_LINK:
95 *link_index = zbuf_get32(&rtapl);
96 break;
97 case IFLA_GRE_IKEY:
98 case IFLA_GRE_OKEY:
99 *gre_key = zbuf_get32(&rtapl);
100 break;
101 case IFLA_GRE_LOCAL:
102 saddr->s_addr = zbuf_get32(&rtapl);
103 break;
104 }
105 }
106 err:
107 zbuf_free(zb);
108 }
109
110 void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index)
111 {
112 struct nlmsghdr *n;
113 struct ifinfomsg *ifi;
114 struct rtattr *rta_info, *rta_data, *rta;
115 struct zbuf *zr = zbuf_alloc(8192), data, rtapl;
116 struct zbuf *zb = zbuf_alloc(8192);
117 size_t len;
118
119 if (__netlink_gre_get_data(zr, &data, ifindex) < 0)
120 goto err;
121
122 n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST);
123 ifi = znl_push(zb, sizeof(*ifi));
124 *ifi = (struct ifinfomsg){
125 .ifi_index = ifindex,
126 };
127 rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO);
128 znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3);
129 rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA);
130
131 znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index);
132 while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
133 if (rta->rta_type == IFLA_GRE_LINK)
134 continue;
135 len = zbuf_used(&rtapl);
136 znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len);
137 }
138
139 znl_rta_nested_complete(zb, rta_data);
140 znl_rta_nested_complete(zb, rta_info);
141
142 znl_nlmsg_complete(zb, n);
143 zbuf_send(zb, netlink_req_fd);
144 zbuf_recv(zb, netlink_req_fd);
145 err:
146 zbuf_free(zb);
147 zbuf_free(zr);
148 }