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 kernel_send_rtmsg_v4 (int action
, mpls_label_t in_label
, zebra_nhlfe_t
*nhlfe
)
45 struct sockaddr_mpls sa_label_in
, sa_label_out
;
46 struct sockaddr_in nexthop
;
50 if (IS_ZEBRA_DEBUG_KERNEL
)
51 zlog_debug ("%s: 0x%x, label=%u", __func__
, action
, in_label
);
53 /* initialize header */
54 memset (&hdr
, 0, sizeof (hdr
));
55 hdr
.rtm_version
= RTM_VERSION
;
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
);
65 iov
[iovcnt
].iov_base
= &hdr
;
66 iov
[iovcnt
++].iov_len
= sizeof (hdr
);
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
);
74 hdr
.rtm_flags
|= RTF_MPLS
| RTF_MPATH
;
75 hdr
.rtm_addrs
|= RTA_DST
;
76 hdr
.rtm_msglen
+= sizeof (sa_label_in
);
78 iov
[iovcnt
].iov_base
= &sa_label_in
;
79 iov
[iovcnt
++].iov_len
= sizeof (sa_label_in
);
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
;
87 hdr
.rtm_flags
|= RTF_GATEWAY
;
88 hdr
.rtm_addrs
|= RTA_GATEWAY
;
89 hdr
.rtm_msglen
+= sizeof (nexthop
);
91 iov
[iovcnt
].iov_base
= &nexthop
;
92 iov
[iovcnt
++].iov_len
= sizeof (nexthop
);
94 /* If action is RTM_DELETE we have to get rid of MPLS infos */
95 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] << MPLS_LABEL_OFFSET
);
103 hdr
.rtm_addrs
|= RTA_SRC
;
104 hdr
.rtm_flags
|= RTF_MPLS
;
105 hdr
.rtm_msglen
+= sizeof (sa_label_out
);
107 iov
[iovcnt
].iov_base
= &sa_label_out
;
108 iov
[iovcnt
++].iov_len
= sizeof (sa_label_out
);
110 if (nhlfe
->nexthop
->nh_label
->label
[0] == MPLS_LABEL_IMPLNULL
)
111 hdr
.rtm_mpls
= MPLS_OP_POP
;
113 hdr
.rtm_mpls
= MPLS_OP_SWAP
;
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");
123 zlog_err ("%s: %s", __func__
, safe_strerror (errno
));
128 #if !defined(ROUNDUP)
130 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
134 kernel_send_rtmsg_v6 (int action
, mpls_label_t in_label
, zebra_nhlfe_t
*nhlfe
)
137 struct rt_msghdr hdr
;
138 struct sockaddr_mpls sa_label_in
, sa_label_out
;
140 struct sockaddr_in6 addr
;
141 char pad
[sizeof(long)]; /* thank you IPv6 */
146 if (IS_ZEBRA_DEBUG_KERNEL
)
147 zlog_debug ("%s: 0x%x, label=%u", __func__
, action
, in_label
);
149 /* initialize header */
150 memset (&hdr
, 0, sizeof (hdr
));
151 hdr
.rtm_version
= RTM_VERSION
;
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;
161 iov
[iovcnt
].iov_base
= &hdr
;
162 iov
[iovcnt
++].iov_len
= sizeof (hdr
);
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
);
170 hdr
.rtm_flags
|= RTF_MPLS
| RTF_MPATH
;
171 hdr
.rtm_addrs
|= RTA_DST
;
172 hdr
.rtm_msglen
+= sizeof (sa_label_in
);
174 iov
[iovcnt
].iov_base
= &sa_label_in
;
175 iov
[iovcnt
++].iov_len
= sizeof (sa_label_in
);
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
))
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
)
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
);
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
));
238 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
)
246 nexthop
= nhlfe
->nexthop
;
250 if (nexthop_num
>= multipath_num
)
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
))))
262 switch (NHLFE_FAMILY(nhlfe
))
265 kernel_send_rtmsg_v4 (action
, lsp
->ile
.in_label
, nhlfe
);
268 kernel_send_rtmsg_v6 (action
, lsp
->ile
.in_label
, nhlfe
);
273 if (action
== RTM_ADD
|| action
== RTM_CHANGE
)
275 SET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
276 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
280 UNSET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
281 UNSET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
290 kernel_add_lsp (zebra_lsp_t
*lsp
)
294 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
297 UNSET_FLAG (lsp
->flags
, LSP_FLAG_CHANGED
);
298 ret
= kernel_lsp_cmd (RTM_ADD
, lsp
);
300 SET_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
);
306 kernel_upd_lsp (zebra_lsp_t
*lsp
)
310 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
313 UNSET_FLAG (lsp
->flags
, LSP_FLAG_CHANGED
);
314 UNSET_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
);
315 ret
= kernel_lsp_cmd (RTM_CHANGE
, lsp
);
317 SET_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
);
323 kernel_del_lsp (zebra_lsp_t
*lsp
)
327 if (!lsp
) // unexpected
330 if (! CHECK_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
))
333 ret
= kernel_lsp_cmd (RTM_DELETE
, lsp
);
335 UNSET_FLAG (lsp
->flags
, LSP_FLAG_INSTALLED
);
340 #define MAX_RTSOCK_BUF 128 * 1024
342 mpls_kernel_init (void)
344 int rcvbuf
, default_rcvbuf
;
347 if ((kr_state
.fd
= socket(AF_ROUTE
, SOCK_RAW
, 0)) == -1) {
348 zlog_warn("%s: socket", __func__
);
352 /* grow receive buffer, don't wanna miss messages */
353 optlen
= sizeof (default_rcvbuf
);
354 if (getsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
,
355 &default_rcvbuf
, &optlen
) == -1)
356 zlog_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
358 for (rcvbuf
= MAX_RTSOCK_BUF
;
359 rcvbuf
> default_rcvbuf
&&
360 setsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
,
361 &rcvbuf
, sizeof (rcvbuf
)) == -1 && errno
== ENOBUFS
;