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
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
23 #include <netmpls/mpls.h>
25 #include "zebra/zebra_mpls.h"
26 #include "zebra/debug.h"
30 #include "interface.h"
33 extern struct zebra_privs_t zserv_privs
;
41 static int kernel_send_rtmsg_v4(int action
, mpls_label_t in_label
,
46 struct sockaddr_mpls sa_label_in
, sa_label_out
;
47 struct sockaddr_in nexthop
;
51 if (IS_ZEBRA_DEBUG_KERNEL
)
52 zlog_debug("%s: 0x%x, label=%u", __func__
, action
, in_label
);
54 /* initialize header */
55 memset(&hdr
, 0, sizeof(hdr
));
56 hdr
.rtm_version
= RTM_VERSION
;
58 hdr
.rtm_type
= action
;
59 hdr
.rtm_flags
= RTF_UP
;
60 hdr
.rtm_fmask
= RTF_MPLS
;
61 hdr
.rtm_seq
= kr_state
.rtseq
++; /* overflow doesn't matter */
62 hdr
.rtm_msglen
= sizeof(hdr
);
63 hdr
.rtm_hdrlen
= sizeof(struct rt_msghdr
);
66 iov
[iovcnt
].iov_base
= &hdr
;
67 iov
[iovcnt
++].iov_len
= sizeof(hdr
);
70 memset(&sa_label_in
, 0, sizeof(sa_label_in
));
71 sa_label_in
.smpls_len
= sizeof(sa_label_in
);
72 sa_label_in
.smpls_family
= AF_MPLS
;
73 sa_label_in
.smpls_label
= htonl(in_label
<< MPLS_LABEL_OFFSET
);
75 hdr
.rtm_flags
|= RTF_MPLS
| RTF_MPATH
;
76 hdr
.rtm_addrs
|= RTA_DST
;
77 hdr
.rtm_msglen
+= sizeof(sa_label_in
);
79 iov
[iovcnt
].iov_base
= &sa_label_in
;
80 iov
[iovcnt
++].iov_len
= sizeof(sa_label_in
);
83 memset(&nexthop
, 0, sizeof(nexthop
));
84 nexthop
.sin_len
= sizeof(nexthop
);
85 nexthop
.sin_family
= AF_INET
;
86 nexthop
.sin_addr
= nhlfe
->nexthop
->gate
.ipv4
;
88 hdr
.rtm_flags
|= RTF_GATEWAY
;
89 hdr
.rtm_addrs
|= RTA_GATEWAY
;
90 hdr
.rtm_msglen
+= sizeof(nexthop
);
92 iov
[iovcnt
].iov_base
= &nexthop
;
93 iov
[iovcnt
++].iov_len
= sizeof(nexthop
);
95 /* If action is RTM_DELETE we have to get rid of MPLS infos */
96 if (action
!= RTM_DELETE
) {
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]
102 << MPLS_LABEL_OFFSET
);
104 hdr
.rtm_addrs
|= RTA_SRC
;
105 hdr
.rtm_flags
|= RTF_MPLS
;
106 hdr
.rtm_msglen
+= sizeof(sa_label_out
);
108 iov
[iovcnt
].iov_base
= &sa_label_out
;
109 iov
[iovcnt
++].iov_len
= sizeof(sa_label_out
);
111 if (nhlfe
->nexthop
->nh_label
->label
[0] == MPLS_LABEL_IMPLNULL
)
112 hdr
.rtm_mpls
= MPLS_OP_POP
;
114 hdr
.rtm_mpls
= MPLS_OP_SWAP
;
117 if (zserv_privs
.change(ZPRIVS_RAISE
))
118 zlog_err("Can't raise privileges");
119 ret
= writev(kr_state
.fd
, iov
, iovcnt
);
120 if (zserv_privs
.change(ZPRIVS_LOWER
))
121 zlog_err("Can't lower privileges");
124 zlog_err("%s: %s", __func__
, safe_strerror(errno
));
129 #if !defined(ROUNDUP)
131 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
134 static int kernel_send_rtmsg_v6(int action
, mpls_label_t in_label
,
135 zebra_nhlfe_t
*nhlfe
)
138 struct rt_msghdr hdr
;
139 struct sockaddr_mpls sa_label_in
, sa_label_out
;
141 struct sockaddr_in6 addr
;
142 char pad
[sizeof(long)]; /* thank you IPv6 */
147 if (IS_ZEBRA_DEBUG_KERNEL
)
148 zlog_debug("%s: 0x%x, label=%u", __func__
, action
, in_label
);
150 /* initialize header */
151 memset(&hdr
, 0, sizeof(hdr
));
152 hdr
.rtm_version
= RTM_VERSION
;
154 hdr
.rtm_type
= action
;
155 hdr
.rtm_flags
= RTF_UP
;
156 hdr
.rtm_fmask
= RTF_MPLS
;
157 hdr
.rtm_seq
= kr_state
.rtseq
++; /* overflow doesn't matter */
158 hdr
.rtm_msglen
= sizeof(hdr
);
159 hdr
.rtm_hdrlen
= sizeof(struct rt_msghdr
);
160 hdr
.rtm_priority
= 0;
162 iov
[iovcnt
].iov_base
= &hdr
;
163 iov
[iovcnt
++].iov_len
= sizeof(hdr
);
166 memset(&sa_label_in
, 0, sizeof(sa_label_in
));
167 sa_label_in
.smpls_len
= sizeof(sa_label_in
);
168 sa_label_in
.smpls_family
= AF_MPLS
;
169 sa_label_in
.smpls_label
= htonl(in_label
<< MPLS_LABEL_OFFSET
);
171 hdr
.rtm_flags
|= RTF_MPLS
| RTF_MPATH
;
172 hdr
.rtm_addrs
|= RTA_DST
;
173 hdr
.rtm_msglen
+= sizeof(sa_label_in
);
175 iov
[iovcnt
].iov_base
= &sa_label_in
;
176 iov
[iovcnt
++].iov_len
= sizeof(sa_label_in
);
179 memset(&nexthop
, 0, sizeof(nexthop
));
180 nexthop
.addr
.sin6_len
= sizeof(struct sockaddr_in6
);
181 nexthop
.addr
.sin6_family
= AF_INET6
;
182 nexthop
.addr
.sin6_addr
= nhlfe
->nexthop
->gate
.ipv6
;
183 if (IN6_IS_ADDR_LINKLOCAL(&nexthop
.addr
.sin6_addr
)) {
185 struct sockaddr_in6
*sin6
= &nexthop
.addr
;
187 nexthop
.addr
.sin6_scope_id
= nhlfe
->nexthop
->ifindex
;
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;
196 hdr
.rtm_flags
|= RTF_GATEWAY
;
197 hdr
.rtm_addrs
|= RTA_GATEWAY
;
198 hdr
.rtm_msglen
+= ROUNDUP(sizeof(struct sockaddr_in6
));
200 iov
[iovcnt
].iov_base
= &nexthop
;
201 iov
[iovcnt
++].iov_len
= ROUNDUP(sizeof(struct sockaddr_in6
));
203 /* If action is RTM_DELETE we have to get rid of MPLS infos */
204 if (action
!= RTM_DELETE
) {
205 memset(&sa_label_out
, 0, sizeof(sa_label_out
));
206 sa_label_out
.smpls_len
= sizeof(sa_label_out
);
207 sa_label_out
.smpls_family
= AF_MPLS
;
208 sa_label_out
.smpls_label
=
209 htonl(nhlfe
->nexthop
->nh_label
->label
[0]
210 << MPLS_LABEL_OFFSET
);
212 hdr
.rtm_addrs
|= RTA_SRC
;
213 hdr
.rtm_flags
|= RTF_MPLS
;
214 hdr
.rtm_msglen
+= sizeof(sa_label_out
);
216 iov
[iovcnt
].iov_base
= &sa_label_out
;
217 iov
[iovcnt
++].iov_len
= sizeof(sa_label_out
);
219 if (nhlfe
->nexthop
->nh_label
->label
[0] == MPLS_LABEL_IMPLNULL
)
220 hdr
.rtm_mpls
= MPLS_OP_POP
;
222 hdr
.rtm_mpls
= MPLS_OP_SWAP
;
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");
232 zlog_err("%s: %s", __func__
, safe_strerror(errno
));
237 static int kernel_lsp_cmd(int action
, zebra_lsp_t
*lsp
)
239 zebra_nhlfe_t
*nhlfe
;
240 struct nexthop
*nexthop
= NULL
;
241 unsigned int nexthop_num
= 0;
243 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
) {
244 nexthop
= nhlfe
->nexthop
;
248 if (nexthop_num
>= multipath_num
)
251 if (((action
== RTM_ADD
|| action
== RTM_CHANGE
)
252 && (CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_SELECTED
)
253 && CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
)))
254 || (action
== RTM_DELETE
255 && (CHECK_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
)
256 && CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
)))) {
259 switch (NHLFE_FAMILY(nhlfe
)) {
261 kernel_send_rtmsg_v4(action
, lsp
->ile
.in_label
,
265 kernel_send_rtmsg_v6(action
, lsp
->ile
.in_label
,
271 if (action
== RTM_ADD
|| action
== RTM_CHANGE
) {
272 SET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
273 SET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
);
275 UNSET_FLAG(nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
276 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_FIB
);
284 int kernel_add_lsp(zebra_lsp_t
*lsp
)
288 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
291 UNSET_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
);
292 ret
= kernel_lsp_cmd(RTM_ADD
, lsp
);
294 SET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
299 int kernel_upd_lsp(zebra_lsp_t
*lsp
)
303 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
306 UNSET_FLAG(lsp
->flags
, LSP_FLAG_CHANGED
);
307 UNSET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
308 ret
= kernel_lsp_cmd(RTM_CHANGE
, lsp
);
310 SET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
315 int kernel_del_lsp(zebra_lsp_t
*lsp
)
319 if (!lsp
) // unexpected
322 if (!CHECK_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
))
325 ret
= kernel_lsp_cmd(RTM_DELETE
, lsp
);
327 UNSET_FLAG(lsp
->flags
, LSP_FLAG_INSTALLED
);
332 static int kmpw_install(struct zebra_pw
*pw
)
336 struct sockaddr_storage ss
;
337 struct sockaddr_in
*sa_in
= (struct sockaddr_in
*)&ss
;
338 struct sockaddr_in6
*sa_in6
= (struct sockaddr_in6
*)&ss
;
340 memset(&imr
, 0, sizeof(imr
));
342 case PW_TYPE_ETHERNET
:
343 imr
.imr_type
= IMR_TYPE_ETHERNET
;
345 case PW_TYPE_ETHERNET_TAGGED
:
346 imr
.imr_type
= IMR_TYPE_ETHERNET_TAGGED
;
349 zlog_err("%s: unhandled pseudowire type (%#X)", __func__
,
354 if (pw
->flags
& F_PSEUDOWIRE_CWORD
)
355 imr
.imr_flags
|= IMR_FLAG_CONTROLWORD
;
357 /* pseudowire nexthop */
358 memset(&ss
, 0, sizeof(ss
));
361 sa_in
->sin_family
= AF_INET
;
362 sa_in
->sin_len
= sizeof(struct sockaddr_in
);
363 sa_in
->sin_addr
= pw
->nexthop
.ipv4
;
366 sa_in6
->sin6_family
= AF_INET6
;
367 sa_in6
->sin6_len
= sizeof(struct sockaddr_in6
);
368 sa_in6
->sin6_addr
= pw
->nexthop
.ipv6
;
371 zlog_err("%s: unhandled pseudowire address-family (%u)",
375 memcpy(&imr
.imr_nexthop
, (struct sockaddr
*)&ss
,
376 sizeof(imr
.imr_nexthop
));
378 /* pseudowire local/remote labels */
379 imr
.imr_lshim
.shim_label
= pw
->local_label
;
380 imr
.imr_rshim
.shim_label
= pw
->remote_label
;
383 memset(&ifr
, 0, sizeof(ifr
));
384 strlcpy(ifr
.ifr_name
, pw
->ifname
, sizeof(ifr
.ifr_name
));
385 ifr
.ifr_data
= (caddr_t
)&imr
;
386 if (ioctl(kr_state
.ioctl_fd
, SIOCSETMPWCFG
, &ifr
) == -1) {
387 zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno
));
394 static int kmpw_uninstall(struct zebra_pw
*pw
)
399 memset(&ifr
, 0, sizeof(ifr
));
400 memset(&imr
, 0, sizeof(imr
));
401 strlcpy(ifr
.ifr_name
, pw
->ifname
, sizeof(ifr
.ifr_name
));
402 ifr
.ifr_data
= (caddr_t
)&imr
;
403 if (ioctl(kr_state
.ioctl_fd
, SIOCSETMPWCFG
, &ifr
) == -1) {
404 zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno
));
411 #define MAX_RTSOCK_BUF 128 * 1024
412 int mpls_kernel_init(void)
414 int rcvbuf
, default_rcvbuf
;
417 if ((kr_state
.fd
= socket(AF_ROUTE
, SOCK_RAW
, 0)) == -1) {
418 zlog_warn("%s: socket", __func__
);
422 if ((kr_state
.ioctl_fd
= socket(AF_INET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0))
424 zlog_warn("%s: ioctl socket", __func__
);
428 /* grow receive buffer, don't wanna miss messages */
429 optlen
= sizeof(default_rcvbuf
);
430 if (getsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
, &default_rcvbuf
,
433 zlog_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
435 for (rcvbuf
= MAX_RTSOCK_BUF
;
436 rcvbuf
> default_rcvbuf
437 && setsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
,
446 /* register hook to install/uninstall pseudowires */
447 hook_register(pw_install
, kmpw_install
);
448 hook_register(pw_uninstall
, kmpw_uninstall
);