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