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
;
42 kernel_send_rtmsg_v4 (int action
, mpls_label_t in_label
, zebra_nhlfe_t
*nhlfe
)
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
)
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] << 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))
135 kernel_send_rtmsg_v6 (int action
, mpls_label_t in_label
, 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
))
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
)
207 memset (&sa_label_out
, 0, sizeof (sa_label_out
));
208 sa_label_out
.smpls_len
= sizeof (sa_label_out
);
209 sa_label_out
.smpls_family
= AF_MPLS
;
210 sa_label_out
.smpls_label
=
211 htonl(nhlfe
->nexthop
->nh_label
->label
[0] << 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
));
239 kernel_lsp_cmd (int action
, zebra_lsp_t
*lsp
)
241 zebra_nhlfe_t
*nhlfe
;
242 struct nexthop
*nexthop
= NULL
;
243 unsigned int nexthop_num
= 0;
245 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
)
247 nexthop
= nhlfe
->nexthop
;
251 if (nexthop_num
>= multipath_num
)
254 if (((action
== RTM_ADD
|| action
== RTM_CHANGE
) &&
255 (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_SELECTED
) &&
256 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))) ||
257 (action
== RTM_DELETE
&&
258 (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
) &&
259 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))))
263 switch (NHLFE_FAMILY(nhlfe
))
266 kernel_send_rtmsg_v4 (action
, lsp
->ile
.in_label
, nhlfe
);
269 kernel_send_rtmsg_v6 (action
, lsp
->ile
.in_label
, nhlfe
);
274 if (action
== RTM_ADD
|| action
== RTM_CHANGE
)
276 SET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
277 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
281 UNSET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
282 UNSET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
291 kernel_add_lsp (zebra_lsp_t
*lsp
)
295 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
298 UNSET_FLAG (lsp
->flags
, LSP_FLAG_CHANGED
);
299 ret
= kernel_lsp_cmd (RTM_ADD
, lsp
);
301 SET_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
);
307 kernel_upd_lsp (zebra_lsp_t
*lsp
)
311 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
314 UNSET_FLAG (lsp
->flags
, LSP_FLAG_CHANGED
);
315 UNSET_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
);
316 ret
= kernel_lsp_cmd (RTM_CHANGE
, lsp
);
318 SET_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
);
324 kernel_del_lsp (zebra_lsp_t
*lsp
)
328 if (!lsp
) // unexpected
331 if (! CHECK_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
))
334 ret
= kernel_lsp_cmd (RTM_DELETE
, lsp
);
336 UNSET_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
);
342 kmpw_install (struct zebra_pw
*pw
)
346 struct sockaddr_storage ss
;
347 struct sockaddr_in
*sa_in
= (struct sockaddr_in
*) &ss
;
348 struct sockaddr_in6
*sa_in6
= (struct sockaddr_in6
*) &ss
;
350 memset (&imr
, 0, sizeof (imr
));
353 case PW_TYPE_ETHERNET
:
354 imr
.imr_type
= IMR_TYPE_ETHERNET
;
356 case PW_TYPE_ETHERNET_TAGGED
:
357 imr
.imr_type
= IMR_TYPE_ETHERNET_TAGGED
;
360 zlog_err ("%s: unhandled pseudowire type (%#X)", __func__
,
365 if (pw
->flags
& F_PSEUDOWIRE_CWORD
)
366 imr
.imr_flags
|= IMR_FLAG_CONTROLWORD
;
368 /* pseudowire nexthop */
369 memset (&ss
, 0, sizeof (ss
));
372 sa_in
->sin_family
= AF_INET
;
373 sa_in
->sin_len
= sizeof (struct sockaddr_in
);
374 sa_in
->sin_addr
= pw
->nexthop
.ipv4
;
377 sa_in6
->sin6_family
= AF_INET6
;
378 sa_in6
->sin6_len
= sizeof (struct sockaddr_in6
);
379 sa_in6
->sin6_addr
= pw
->nexthop
.ipv6
;
382 zlog_err ("%s: unhandled pseudowire address-family (%u)", __func__
,
386 memcpy (&imr
.imr_nexthop
, (struct sockaddr
*) &ss
,
387 sizeof (imr
.imr_nexthop
));
389 /* pseudowire local/remote labels */
390 imr
.imr_lshim
.shim_label
= pw
->local_label
;
391 imr
.imr_rshim
.shim_label
= pw
->remote_label
;
394 memset (&ifr
, 0, sizeof (ifr
));
395 strlcpy (ifr
.ifr_name
, pw
->ifname
, sizeof (ifr
.ifr_name
));
396 ifr
.ifr_data
= (caddr_t
) &imr
;
397 if (ioctl (kr_state
.ioctl_fd
, SIOCSETMPWCFG
, &ifr
) == -1)
399 zlog_err ("ioctl SIOCSETMPWCFG: %s", safe_strerror (errno
));
407 kmpw_uninstall (struct zebra_pw
*pw
)
412 memset(&ifr
, 0, sizeof (ifr
));
413 memset(&imr
, 0, sizeof (imr
));
414 strlcpy (ifr
.ifr_name
, pw
->ifname
, sizeof (ifr
.ifr_name
));
415 ifr
.ifr_data
= (caddr_t
) &imr
;
416 if (ioctl (kr_state
.ioctl_fd
, SIOCSETMPWCFG
, &ifr
) == -1)
418 zlog_err ("ioctl SIOCSETMPWCFG: %s", safe_strerror (errno
));
425 #define MAX_RTSOCK_BUF 128 * 1024
427 mpls_kernel_init (void)
429 int rcvbuf
, default_rcvbuf
;
432 if ((kr_state
.fd
= socket(AF_ROUTE
, SOCK_RAW
, 0)) == -1)
434 zlog_warn("%s: socket", __func__
);
438 if ((kr_state
.ioctl_fd
= socket(AF_INET
, SOCK_DGRAM
| SOCK_NONBLOCK
, 0)) == -1)
440 zlog_warn("%s: ioctl socket", __func__
);
444 /* grow receive buffer, don't wanna miss messages */
445 optlen
= sizeof (default_rcvbuf
);
446 if (getsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
,
447 &default_rcvbuf
, &optlen
) == -1)
448 zlog_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
450 for (rcvbuf
= MAX_RTSOCK_BUF
;
451 rcvbuf
> default_rcvbuf
&&
452 setsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
,
453 &rcvbuf
, sizeof (rcvbuf
)) == -1 && errno
== ENOBUFS
;
459 /* register hook to install/uninstall pseudowires */
460 hook_register (pw_install
, kmpw_install
);
461 hook_register (pw_uninstall
, kmpw_uninstall
);