]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mpls_openbsd.c
Merge branch 'master' into pim-ssm
[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
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
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
33 extern struct zebra_privs_t zserv_privs;
34
35 struct {
36 u_int32_t rtseq;
37 int fd;
38 } kr_state;
39
40 static int
41 kernel_send_rtmsg_v4 (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
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)
51 zlog_debug ("%s: 0x%x, label=%u", __func__, action, in_label);
52
53 /* initialize header */
54 memset (&hdr, 0, sizeof (hdr));
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 */
69 memset (&sa_label_in, 0, sizeof (sa_label_in));
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 */
82 memset (&nexthop, 0, sizeof (nexthop));
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 {
97 memset (&sa_label_out, 0, sizeof (sa_label_out));
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)
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
133 static int
134 kernel_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 */
150 memset (&hdr, 0, sizeof (hdr));
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 */
165 memset (&sa_label_in, 0, sizeof (sa_label_in));
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 {
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] << 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));
233
234 return ret;
235 }
236
237 static int
238 kernel_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
250 if (nexthop_num >= multipath_num)
251 break;
252
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
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 }
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
289 int
290 kernel_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
298 int
299 kernel_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
307 int
308 kernel_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
317 int
318 mpls_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) {
324 zlog_warn("%s: socket", __func__);
325 return -1;
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;
342
343 return 0;
344 }