2 * Copyright (C) 2016 by Open Source Routing.
4 * This file is part of GNU Zebra.
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
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.
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
25 #include <netmpls/mpls.h>
27 #include "zebra/zebra_mpls.h"
28 #include "zebra/debug.h"
32 #include "interface.h"
35 extern struct zebra_privs_t zserv_privs
;
42 static int kernel_send_rtmsg_v4(int action
, mpls_label_t in_label
,
47 struct sockaddr_mpls sa_label_in
, sa_label_out
;
48 struct sockaddr_in nexthop
;
52 if (IS_ZEBRA_DEBUG_KERNEL
)
53 zlog_debug("%s: 0x%x, label=%u", __func__
, action
, in_label
);
55 /* initialize header */
56 memset(&hdr
, 0, sizeof(hdr
));
57 hdr
.rtm_version
= RTM_VERSION
;
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
);
67 iov
[iovcnt
].iov_base
= &hdr
;
68 iov
[iovcnt
++].iov_len
= sizeof(hdr
);
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
);
76 hdr
.rtm_flags
|= RTF_MPLS
| RTF_MPATH
;
77 hdr
.rtm_addrs
|= RTA_DST
;
78 hdr
.rtm_msglen
+= sizeof(sa_label_in
);
80 iov
[iovcnt
].iov_base
= &sa_label_in
;
81 iov
[iovcnt
++].iov_len
= sizeof(sa_label_in
);
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
;
89 hdr
.rtm_flags
|= RTF_GATEWAY
;
90 hdr
.rtm_addrs
|= RTA_GATEWAY
;
91 hdr
.rtm_msglen
+= sizeof(nexthop
);
93 iov
[iovcnt
].iov_base
= &nexthop
;
94 iov
[iovcnt
++].iov_len
= sizeof(nexthop
);
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
);
105 hdr
.rtm_addrs
|= RTA_SRC
;
106 hdr
.rtm_flags
|= RTF_MPLS
;
107 hdr
.rtm_msglen
+= sizeof(sa_label_out
);
109 iov
[iovcnt
].iov_base
= &sa_label_out
;
110 iov
[iovcnt
++].iov_len
= sizeof(sa_label_out
);
112 if (nhlfe
->nexthop
->nh_label
->label
[0] == MPLS_LABEL_IMPLNULL
)
113 hdr
.rtm_mpls
= MPLS_OP_POP
;
115 hdr
.rtm_mpls
= MPLS_OP_SWAP
;
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");
125 zlog_err("%s: %s", __func__
, safe_strerror(errno
));
130 #if !defined(ROUNDUP)
132 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
135 static int kernel_send_rtmsg_v6(int action
, mpls_label_t in_label
,
136 zebra_nhlfe_t
*nhlfe
)
139 struct rt_msghdr hdr
;
140 struct sockaddr_mpls sa_label_in
, sa_label_out
;
142 struct sockaddr_in6 addr
;
143 char pad
[sizeof(long)]; /* thank you IPv6 */
148 if (IS_ZEBRA_DEBUG_KERNEL
)
149 zlog_debug("%s: 0x%x, label=%u", __func__
, action
, in_label
);
151 /* initialize header */
152 memset(&hdr
, 0, sizeof(hdr
));
153 hdr
.rtm_version
= RTM_VERSION
;
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;
163 iov
[iovcnt
].iov_base
= &hdr
;
164 iov
[iovcnt
++].iov_len
= sizeof(hdr
);
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
);
172 hdr
.rtm_flags
|= RTF_MPLS
| RTF_MPATH
;
173 hdr
.rtm_addrs
|= RTA_DST
;
174 hdr
.rtm_msglen
+= sizeof(sa_label_in
);
176 iov
[iovcnt
].iov_base
= &sa_label_in
;
177 iov
[iovcnt
++].iov_len
= sizeof(sa_label_in
);
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
)) {
186 struct sockaddr_in6
*sin6
= &nexthop
.addr
;
188 nexthop
.addr
.sin6_scope_id
= nhlfe
->nexthop
->ifindex
;
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;
197 hdr
.rtm_flags
|= RTF_GATEWAY
;
198 hdr
.rtm_addrs
|= RTA_GATEWAY
;
199 hdr
.rtm_msglen
+= ROUNDUP(sizeof(struct sockaddr_in6
));
201 iov
[iovcnt
].iov_base
= &nexthop
;
202 iov
[iovcnt
++].iov_len
= ROUNDUP(sizeof(struct sockaddr_in6
));
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
);
213 hdr
.rtm_addrs
|= RTA_SRC
;
214 hdr
.rtm_flags
|= RTF_MPLS
;
215 hdr
.rtm_msglen
+= sizeof(sa_label_out
);
217 iov
[iovcnt
].iov_base
= &sa_label_out
;
218 iov
[iovcnt
++].iov_len
= sizeof(sa_label_out
);
220 if (nhlfe
->nexthop
->nh_label
->label
[0] == MPLS_LABEL_IMPLNULL
)
221 hdr
.rtm_mpls
= MPLS_OP_POP
;
223 hdr
.rtm_mpls
= MPLS_OP_SWAP
;
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");
233 zlog_err("%s: %s", __func__
, safe_strerror(errno
));
238 static int kernel_lsp_cmd(int action
, zebra_lsp_t
*lsp
)
240 zebra_nhlfe_t
*nhlfe
;
241 struct nexthop
*nexthop
= NULL
;
242 unsigned int nexthop_num
= 0;
244 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
) {
245 nexthop
= nhlfe
->nexthop
;
249 if (nexthop_num
>= multipath_num
)
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
)))) {
260 switch (NHLFE_FAMILY(nhlfe
)) {
262 kernel_send_rtmsg_v4(action
, lsp
->ile
.in_label
,
266 kernel_send_rtmsg_v6(action
, lsp
->ile
.in_label
,
272 if (action
== RTM_ADD
|| action
== RTM_CHANGE
) {
273 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
274 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
);
276 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
277 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
);
285 int kernel_add_lsp(zebra_lsp_t
*lsp
)
289 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
292 UNSET_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
);
293 ret
= kernel_lsp_cmd(RTM_ADD
, lsp
);
295 SET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
300 int kernel_upd_lsp(zebra_lsp_t
*lsp
)
304 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
307 UNSET_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
);
308 UNSET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
309 ret
= kernel_lsp_cmd(RTM_CHANGE
, lsp
);
311 SET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
316 int kernel_del_lsp(zebra_lsp_t
*lsp
)
320 if (!lsp
) // unexpected
323 if (!CHECK_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
))
326 ret
= kernel_lsp_cmd(RTM_DELETE
, lsp
);
328 UNSET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
333 #define MAX_RTSOCK_BUF 128 * 1024
334 int mpls_kernel_init(void)
336 int rcvbuf
, default_rcvbuf
;
339 if ((kr_state
.fd
= socket(AF_ROUTE
, SOCK_RAW
, 0)) == -1) {
340 zlog_warn("%s: socket", __func__
);
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
,
349 zlog_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
351 for (rcvbuf
= MAX_RTSOCK_BUF
;
352 rcvbuf
> default_rcvbuf
353 && setsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
,
365 #endif /* OPEN_BSD */