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
22 #include <netmpls/mpls.h>
24 #include "zebra/zebra_mpls.h"
25 #include "zebra/debug.h"
29 #include "interface.h"
32 extern struct zebra_privs_t zserv_privs
;
40 kernel_send_rtmsg_v4 (int action
, mpls_label_t in_label
, zebra_nhlfe_t
*nhlfe
)
44 struct sockaddr_mpls sa_label_in
, sa_label_out
;
45 struct sockaddr_in nexthop
;
49 if (IS_ZEBRA_DEBUG_KERNEL
)
50 zlog_debug ("%s: 0x%x, label=%u", __func__
, action
, in_label
);
52 /* initialize header */
53 memset (&hdr
, 0, sizeof (hdr
));
54 hdr
.rtm_version
= RTM_VERSION
;
56 hdr
.rtm_type
= action
;
57 hdr
.rtm_flags
= RTF_UP
;
58 hdr
.rtm_fmask
= RTF_MPLS
;
59 hdr
.rtm_seq
= kr_state
.rtseq
++; /* overflow doesn't matter */
60 hdr
.rtm_msglen
= sizeof (hdr
);
61 hdr
.rtm_hdrlen
= sizeof (struct rt_msghdr
);
64 iov
[iovcnt
].iov_base
= &hdr
;
65 iov
[iovcnt
++].iov_len
= sizeof (hdr
);
68 memset (&sa_label_in
, 0, sizeof (sa_label_in
));
69 sa_label_in
.smpls_len
= sizeof (sa_label_in
);
70 sa_label_in
.smpls_family
= AF_MPLS
;
71 sa_label_in
.smpls_label
= htonl(in_label
<< MPLS_LABEL_OFFSET
);
73 hdr
.rtm_flags
|= RTF_MPLS
| RTF_MPATH
;
74 hdr
.rtm_addrs
|= RTA_DST
;
75 hdr
.rtm_msglen
+= sizeof (sa_label_in
);
77 iov
[iovcnt
].iov_base
= &sa_label_in
;
78 iov
[iovcnt
++].iov_len
= sizeof (sa_label_in
);
81 memset (&nexthop
, 0, sizeof (nexthop
));
82 nexthop
.sin_len
= sizeof (nexthop
);
83 nexthop
.sin_family
= AF_INET
;
84 nexthop
.sin_addr
= nhlfe
->nexthop
->gate
.ipv4
;
86 hdr
.rtm_flags
|= RTF_GATEWAY
;
87 hdr
.rtm_addrs
|= RTA_GATEWAY
;
88 hdr
.rtm_msglen
+= sizeof (nexthop
);
90 iov
[iovcnt
].iov_base
= &nexthop
;
91 iov
[iovcnt
++].iov_len
= sizeof (nexthop
);
93 /* If action is RTM_DELETE we have to get rid of MPLS infos */
94 if (action
!= RTM_DELETE
)
96 memset (&sa_label_out
, 0, sizeof (sa_label_out
));
97 sa_label_out
.smpls_len
= sizeof (sa_label_out
);
98 sa_label_out
.smpls_family
= AF_MPLS
;
99 sa_label_out
.smpls_label
=
100 htonl(nhlfe
->nexthop
->nh_label
->label
[0] << MPLS_LABEL_OFFSET
);
102 hdr
.rtm_addrs
|= RTA_SRC
;
103 hdr
.rtm_flags
|= RTF_MPLS
;
104 hdr
.rtm_msglen
+= sizeof (sa_label_out
);
106 iov
[iovcnt
].iov_base
= &sa_label_out
;
107 iov
[iovcnt
++].iov_len
= sizeof (sa_label_out
);
109 if (nhlfe
->nexthop
->nh_label
->label
[0] == MPLS_LABEL_IMPLNULL
)
110 hdr
.rtm_mpls
= MPLS_OP_POP
;
112 hdr
.rtm_mpls
= MPLS_OP_SWAP
;
115 if (zserv_privs
.change(ZPRIVS_RAISE
))
116 zlog_err ("Can't raise privileges");
117 ret
= writev (kr_state
.fd
, iov
, iovcnt
);
118 if (zserv_privs
.change(ZPRIVS_LOWER
))
119 zlog_err ("Can't lower privileges");
122 zlog_err ("%s: %s", __func__
, safe_strerror (errno
));
127 #if !defined(ROUNDUP)
129 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
133 kernel_send_rtmsg_v6 (int action
, mpls_label_t in_label
, zebra_nhlfe_t
*nhlfe
)
136 struct rt_msghdr hdr
;
137 struct sockaddr_mpls sa_label_in
, sa_label_out
;
139 struct sockaddr_in6 addr
;
140 char pad
[sizeof(long)]; /* thank you IPv6 */
145 if (IS_ZEBRA_DEBUG_KERNEL
)
146 zlog_debug ("%s: 0x%x, label=%u", __func__
, action
, in_label
);
148 /* initialize header */
149 memset (&hdr
, 0, sizeof (hdr
));
150 hdr
.rtm_version
= RTM_VERSION
;
152 hdr
.rtm_type
= action
;
153 hdr
.rtm_flags
= RTF_UP
;
154 hdr
.rtm_fmask
= RTF_MPLS
;
155 hdr
.rtm_seq
= kr_state
.rtseq
++; /* overflow doesn't matter */
156 hdr
.rtm_msglen
= sizeof (hdr
);
157 hdr
.rtm_hdrlen
= sizeof (struct rt_msghdr
);
158 hdr
.rtm_priority
= 0;
160 iov
[iovcnt
].iov_base
= &hdr
;
161 iov
[iovcnt
++].iov_len
= sizeof (hdr
);
164 memset (&sa_label_in
, 0, sizeof (sa_label_in
));
165 sa_label_in
.smpls_len
= sizeof (sa_label_in
);
166 sa_label_in
.smpls_family
= AF_MPLS
;
167 sa_label_in
.smpls_label
= htonl(in_label
<< MPLS_LABEL_OFFSET
);
169 hdr
.rtm_flags
|= RTF_MPLS
| RTF_MPATH
;
170 hdr
.rtm_addrs
|= RTA_DST
;
171 hdr
.rtm_msglen
+= sizeof (sa_label_in
);
173 iov
[iovcnt
].iov_base
= &sa_label_in
;
174 iov
[iovcnt
++].iov_len
= sizeof (sa_label_in
);
177 memset (&nexthop
, 0, sizeof (nexthop
));
178 nexthop
.addr
.sin6_len
= sizeof (struct sockaddr_in6
);
179 nexthop
.addr
.sin6_family
= AF_INET6
;
180 nexthop
.addr
.sin6_addr
= nhlfe
->nexthop
->gate
.ipv6
;
181 if (IN6_IS_ADDR_LINKLOCAL (&nexthop
.addr
.sin6_addr
))
184 struct sockaddr_in6
*sin6
= &nexthop
.addr
;
186 nexthop
.addr
.sin6_scope_id
= nhlfe
->nexthop
->ifindex
;
188 memcpy (&tmp16
, &sin6
->sin6_addr
.s6_addr
[2], sizeof (tmp16
));
189 tmp16
= htons (sin6
->sin6_scope_id
);
190 memcpy (&sin6
->sin6_addr
.s6_addr
[2], &tmp16
, sizeof (tmp16
));
191 sin6
->sin6_scope_id
= 0;
195 hdr
.rtm_flags
|= RTF_GATEWAY
;
196 hdr
.rtm_addrs
|= RTA_GATEWAY
;
197 hdr
.rtm_msglen
+= ROUNDUP (sizeof (struct sockaddr_in6
));
199 iov
[iovcnt
].iov_base
= &nexthop
;
200 iov
[iovcnt
++].iov_len
= ROUNDUP (sizeof (struct sockaddr_in6
));
202 /* If action is RTM_DELETE we have to get rid of MPLS infos */
203 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] << MPLS_LABEL_OFFSET
);
211 hdr
.rtm_addrs
|= RTA_SRC
;
212 hdr
.rtm_flags
|= RTF_MPLS
;
213 hdr
.rtm_msglen
+= sizeof (sa_label_out
);
215 iov
[iovcnt
].iov_base
= &sa_label_out
;
216 iov
[iovcnt
++].iov_len
= sizeof (sa_label_out
);
218 if (nhlfe
->nexthop
->nh_label
->label
[0] == MPLS_LABEL_IMPLNULL
)
219 hdr
.rtm_mpls
= MPLS_OP_POP
;
221 hdr
.rtm_mpls
= MPLS_OP_SWAP
;
224 if (zserv_privs
.change(ZPRIVS_RAISE
))
225 zlog_err ("Can't raise privileges");
226 ret
= writev (kr_state
.fd
, iov
, iovcnt
);
227 if (zserv_privs
.change(ZPRIVS_LOWER
))
228 zlog_err ("Can't lower privileges");
231 zlog_err ("%s: %s", __func__
, safe_strerror (errno
));
237 kernel_lsp_cmd (int action
, zebra_lsp_t
*lsp
)
239 zebra_nhlfe_t
*nhlfe
;
240 struct nexthop
*nexthop
= NULL
;
243 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
))))
261 switch (NHLFE_FAMILY(nhlfe
))
264 kernel_send_rtmsg_v4 (action
, lsp
->ile
.in_label
, nhlfe
);
267 kernel_send_rtmsg_v6 (action
, lsp
->ile
.in_label
, nhlfe
);
272 if (action
== RTM_ADD
|| action
== RTM_CHANGE
)
274 SET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
275 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
279 UNSET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
280 UNSET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
289 kernel_add_lsp (zebra_lsp_t
*lsp
)
291 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
294 return kernel_lsp_cmd (RTM_ADD
, lsp
);
298 kernel_upd_lsp (zebra_lsp_t
*lsp
)
300 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
303 return kernel_lsp_cmd (RTM_CHANGE
, lsp
);
307 kernel_del_lsp (zebra_lsp_t
*lsp
)
309 if (!lsp
) // unexpected
312 return kernel_lsp_cmd (RTM_DELETE
, lsp
);
315 #define MAX_RTSOCK_BUF 128 * 1024
317 mpls_kernel_init (void)
319 int rcvbuf
, default_rcvbuf
;
322 if ((kr_state
.fd
= socket(AF_ROUTE
, SOCK_RAW
, 0)) == -1) {
323 zlog_warn("%s: socket", __func__
);
327 /* grow receive buffer, don't wanna miss messages */
328 optlen
= sizeof (default_rcvbuf
);
329 if (getsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
,
330 &default_rcvbuf
, &optlen
) == -1)
331 zlog_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
333 for (rcvbuf
= MAX_RTSOCK_BUF
;
334 rcvbuf
> default_rcvbuf
&&
335 setsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
,
336 &rcvbuf
, sizeof (rcvbuf
)) == -1 && errno
== ENOBUFS
;