]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mpls_openbsd.c
build: zebra: remove *_method Makefile hacks
[mirror_frr.git] / zebra / zebra_mpls_openbsd.c
1 /*
2 * Copyright (C) 2016 by Open Source Routing.
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #ifdef OPEN_BSD
24
25 #include <netmpls/mpls.h>
26 #include "zebra/rt.h"
27 #include "zebra/zebra_mpls.h"
28 #include "zebra/debug.h"
29
30 #include "privs.h"
31 #include "prefix.h"
32 #include "interface.h"
33 #include "log.h"
34
35 extern struct zebra_privs_t zserv_privs;
36
37 struct {
38 u_int32_t rtseq;
39 int fd;
40 } kr_state;
41
42 static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
43 zebra_nhlfe_t *nhlfe)
44 {
45 struct iovec iov[5];
46 struct rt_msghdr hdr;
47 struct sockaddr_mpls sa_label_in, sa_label_out;
48 struct sockaddr_in nexthop;
49 int iovcnt = 0;
50 int ret;
51
52 if (IS_ZEBRA_DEBUG_KERNEL)
53 zlog_debug("%s: 0x%x, label=%u", __func__, action, in_label);
54
55 /* initialize header */
56 memset(&hdr, 0, sizeof(hdr));
57 hdr.rtm_version = RTM_VERSION;
58
59 hdr.rtm_type = action;
60 hdr.rtm_flags = RTF_UP;
61 hdr.rtm_fmask = RTF_MPLS;
62 hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */
63 hdr.rtm_msglen = sizeof(hdr);
64 hdr.rtm_hdrlen = sizeof(struct rt_msghdr);
65 hdr.rtm_priority = 0;
66 /* adjust iovec */
67 iov[iovcnt].iov_base = &hdr;
68 iov[iovcnt++].iov_len = sizeof(hdr);
69
70 /* in label */
71 memset(&sa_label_in, 0, sizeof(sa_label_in));
72 sa_label_in.smpls_len = sizeof(sa_label_in);
73 sa_label_in.smpls_family = AF_MPLS;
74 sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET);
75 /* adjust header */
76 hdr.rtm_flags |= RTF_MPLS | RTF_MPATH;
77 hdr.rtm_addrs |= RTA_DST;
78 hdr.rtm_msglen += sizeof(sa_label_in);
79 /* adjust iovec */
80 iov[iovcnt].iov_base = &sa_label_in;
81 iov[iovcnt++].iov_len = sizeof(sa_label_in);
82
83 /* nexthop */
84 memset(&nexthop, 0, sizeof(nexthop));
85 nexthop.sin_len = sizeof(nexthop);
86 nexthop.sin_family = AF_INET;
87 nexthop.sin_addr = nhlfe->nexthop->gate.ipv4;
88 /* adjust header */
89 hdr.rtm_flags |= RTF_GATEWAY;
90 hdr.rtm_addrs |= RTA_GATEWAY;
91 hdr.rtm_msglen += sizeof(nexthop);
92 /* adjust iovec */
93 iov[iovcnt].iov_base = &nexthop;
94 iov[iovcnt++].iov_len = sizeof(nexthop);
95
96 /* If action is RTM_DELETE we have to get rid of MPLS infos */
97 if (action != RTM_DELETE) {
98 memset(&sa_label_out, 0, sizeof(sa_label_out));
99 sa_label_out.smpls_len = sizeof(sa_label_out);
100 sa_label_out.smpls_family = AF_MPLS;
101 sa_label_out.smpls_label =
102 htonl(nhlfe->nexthop->nh_label->label[0]
103 << MPLS_LABEL_OFFSET);
104 /* adjust header */
105 hdr.rtm_addrs |= RTA_SRC;
106 hdr.rtm_flags |= RTF_MPLS;
107 hdr.rtm_msglen += sizeof(sa_label_out);
108 /* adjust iovec */
109 iov[iovcnt].iov_base = &sa_label_out;
110 iov[iovcnt++].iov_len = sizeof(sa_label_out);
111
112 if (nhlfe->nexthop->nh_label->label[0] == MPLS_LABEL_IMPLNULL)
113 hdr.rtm_mpls = MPLS_OP_POP;
114 else
115 hdr.rtm_mpls = MPLS_OP_SWAP;
116 }
117
118 if (zserv_privs.change(ZPRIVS_RAISE))
119 zlog_err("Can't raise privileges");
120 ret = writev(kr_state.fd, iov, iovcnt);
121 if (zserv_privs.change(ZPRIVS_LOWER))
122 zlog_err("Can't lower privileges");
123
124 if (ret == -1)
125 zlog_err("%s: %s", __func__, safe_strerror(errno));
126
127 return ret;
128 }
129
130 #if !defined(ROUNDUP)
131 #define ROUNDUP(a) \
132 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
133 #endif
134
135 static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label,
136 zebra_nhlfe_t *nhlfe)
137 {
138 struct iovec iov[5];
139 struct rt_msghdr hdr;
140 struct sockaddr_mpls sa_label_in, sa_label_out;
141 struct pad {
142 struct sockaddr_in6 addr;
143 char pad[sizeof(long)]; /* thank you IPv6 */
144 } nexthop;
145 int iovcnt = 0;
146 int ret;
147
148 if (IS_ZEBRA_DEBUG_KERNEL)
149 zlog_debug("%s: 0x%x, label=%u", __func__, action, in_label);
150
151 /* initialize header */
152 memset(&hdr, 0, sizeof(hdr));
153 hdr.rtm_version = RTM_VERSION;
154
155 hdr.rtm_type = action;
156 hdr.rtm_flags = RTF_UP;
157 hdr.rtm_fmask = RTF_MPLS;
158 hdr.rtm_seq = kr_state.rtseq++; /* overflow doesn't matter */
159 hdr.rtm_msglen = sizeof(hdr);
160 hdr.rtm_hdrlen = sizeof(struct rt_msghdr);
161 hdr.rtm_priority = 0;
162 /* adjust iovec */
163 iov[iovcnt].iov_base = &hdr;
164 iov[iovcnt++].iov_len = sizeof(hdr);
165
166 /* in label */
167 memset(&sa_label_in, 0, sizeof(sa_label_in));
168 sa_label_in.smpls_len = sizeof(sa_label_in);
169 sa_label_in.smpls_family = AF_MPLS;
170 sa_label_in.smpls_label = htonl(in_label << MPLS_LABEL_OFFSET);
171 /* adjust header */
172 hdr.rtm_flags |= RTF_MPLS | RTF_MPATH;
173 hdr.rtm_addrs |= RTA_DST;
174 hdr.rtm_msglen += sizeof(sa_label_in);
175 /* adjust iovec */
176 iov[iovcnt].iov_base = &sa_label_in;
177 iov[iovcnt++].iov_len = sizeof(sa_label_in);
178
179 /* nexthop */
180 memset(&nexthop, 0, sizeof(nexthop));
181 nexthop.addr.sin6_len = sizeof(struct sockaddr_in6);
182 nexthop.addr.sin6_family = AF_INET6;
183 nexthop.addr.sin6_addr = nhlfe->nexthop->gate.ipv6;
184 if (IN6_IS_ADDR_LINKLOCAL(&nexthop.addr.sin6_addr)) {
185 uint16_t tmp16;
186 struct sockaddr_in6 *sin6 = &nexthop.addr;
187
188 nexthop.addr.sin6_scope_id = nhlfe->nexthop->ifindex;
189
190 memcpy(&tmp16, &sin6->sin6_addr.s6_addr[2], sizeof(tmp16));
191 tmp16 = htons(sin6->sin6_scope_id);
192 memcpy(&sin6->sin6_addr.s6_addr[2], &tmp16, sizeof(tmp16));
193 sin6->sin6_scope_id = 0;
194 }
195
196 /* adjust header */
197 hdr.rtm_flags |= RTF_GATEWAY;
198 hdr.rtm_addrs |= RTA_GATEWAY;
199 hdr.rtm_msglen += ROUNDUP(sizeof(struct sockaddr_in6));
200 /* adjust iovec */
201 iov[iovcnt].iov_base = &nexthop;
202 iov[iovcnt++].iov_len = ROUNDUP(sizeof(struct sockaddr_in6));
203
204 /* If action is RTM_DELETE we have to get rid of MPLS infos */
205 if (action != RTM_DELETE) {
206 memset(&sa_label_out, 0, sizeof(sa_label_out));
207 sa_label_out.smpls_len = sizeof(sa_label_out);
208 sa_label_out.smpls_family = AF_MPLS;
209 sa_label_out.smpls_label =
210 htonl(nhlfe->nexthop->nh_label->label[0]
211 << MPLS_LABEL_OFFSET);
212 /* adjust header */
213 hdr.rtm_addrs |= RTA_SRC;
214 hdr.rtm_flags |= RTF_MPLS;
215 hdr.rtm_msglen += sizeof(sa_label_out);
216 /* adjust iovec */
217 iov[iovcnt].iov_base = &sa_label_out;
218 iov[iovcnt++].iov_len = sizeof(sa_label_out);
219
220 if (nhlfe->nexthop->nh_label->label[0] == MPLS_LABEL_IMPLNULL)
221 hdr.rtm_mpls = MPLS_OP_POP;
222 else
223 hdr.rtm_mpls = MPLS_OP_SWAP;
224 }
225
226 if (zserv_privs.change(ZPRIVS_RAISE))
227 zlog_err("Can't raise privileges");
228 ret = writev(kr_state.fd, iov, iovcnt);
229 if (zserv_privs.change(ZPRIVS_LOWER))
230 zlog_err("Can't lower privileges");
231
232 if (ret == -1)
233 zlog_err("%s: %s", __func__, safe_strerror(errno));
234
235 return ret;
236 }
237
238 static int kernel_lsp_cmd(int action, zebra_lsp_t *lsp)
239 {
240 zebra_nhlfe_t *nhlfe;
241 struct nexthop *nexthop = NULL;
242 unsigned int nexthop_num = 0;
243
244 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
245 nexthop = nhlfe->nexthop;
246 if (!nexthop)
247 continue;
248
249 if (nexthop_num >= multipath_num)
250 break;
251
252 if (((action == RTM_ADD || action == RTM_CHANGE)
253 && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
254 && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)))
255 || (action == RTM_DELETE
256 && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)
257 && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)))) {
258 nexthop_num++;
259
260 switch (NHLFE_FAMILY(nhlfe)) {
261 case AF_INET:
262 kernel_send_rtmsg_v4(action, lsp->ile.in_label,
263 nhlfe);
264 break;
265 case AF_INET6:
266 kernel_send_rtmsg_v6(action, lsp->ile.in_label,
267 nhlfe);
268 break;
269 default:
270 break;
271 }
272 if (action == RTM_ADD || action == RTM_CHANGE) {
273 SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
274 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
275 } else {
276 UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
277 UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
278 }
279 }
280 }
281
282 return (0);
283 }
284
285 int kernel_add_lsp(zebra_lsp_t *lsp)
286 {
287 int ret;
288
289 if (!lsp || !lsp->best_nhlfe) // unexpected
290 return -1;
291
292 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
293 ret = kernel_lsp_cmd(RTM_ADD, lsp);
294 if (!ret)
295 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
296
297 return ret;
298 }
299
300 int kernel_upd_lsp(zebra_lsp_t *lsp)
301 {
302 int ret;
303
304 if (!lsp || !lsp->best_nhlfe) // unexpected
305 return -1;
306
307 UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
308 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
309 ret = kernel_lsp_cmd(RTM_CHANGE, lsp);
310 if (!ret)
311 SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
312
313 return ret;
314 }
315
316 int kernel_del_lsp(zebra_lsp_t *lsp)
317 {
318 int ret;
319
320 if (!lsp) // unexpected
321 return -1;
322
323 if (!CHECK_FLAG(lsp->flags, LSP_FLAG_INSTALLED))
324 return -1;
325
326 ret = kernel_lsp_cmd(RTM_DELETE, lsp);
327 if (!ret)
328 UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
329
330 return ret;
331 }
332
333 #define MAX_RTSOCK_BUF 128 * 1024
334 int mpls_kernel_init(void)
335 {
336 int rcvbuf, default_rcvbuf;
337 socklen_t optlen;
338
339 if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
340 zlog_warn("%s: socket", __func__);
341 return -1;
342 }
343
344 /* grow receive buffer, don't wanna miss messages */
345 optlen = sizeof(default_rcvbuf);
346 if (getsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &default_rcvbuf,
347 &optlen)
348 == -1)
349 zlog_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
350 else
351 for (rcvbuf = MAX_RTSOCK_BUF;
352 rcvbuf > default_rcvbuf
353 && setsockopt(kr_state.fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
354 sizeof(rcvbuf))
355 == -1
356 && errno == ENOBUFS;
357 rcvbuf /= 2)
358 ; /* nothing */
359
360 kr_state.rtseq = 1;
361
362 return 0;
363 }
364
365 #endif /* OPEN_BSD */