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 (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 ("kernel_send_rtmsg: 0x%x, label=%u", action
, in_label
);
53 /* initialize header */
54 bzero(&hdr
, 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 bzero(&sa_label_in
, 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 bzero(&nexthop
, 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 bzero(&sa_label_out
, 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 ("kernel_send_rtmsg: %s", safe_strerror (errno
));
129 kernel_lsp_cmd (int action
, zebra_lsp_t
*lsp
)
131 zebra_nhlfe_t
*nhlfe
;
132 struct nexthop
*nexthop
= NULL
;
135 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
)
137 nexthop
= nhlfe
->nexthop
;
141 if (MULTIPATH_NUM
!= 0 && nexthop_num
>= MULTIPATH_NUM
)
145 if (NHLFE_FAMILY(nhlfe
) == AF_INET6
)
148 if (((action
== RTM_ADD
|| action
== RTM_CHANGE
) &&
149 (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_SELECTED
) &&
150 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))) ||
151 (action
== RTM_DELETE
&&
152 (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
) &&
153 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))))
157 kernel_send_rtmsg (action
, lsp
->ile
.in_label
, nhlfe
);
158 if (action
== RTM_ADD
|| action
== RTM_CHANGE
)
160 SET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
161 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
165 UNSET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
166 UNSET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
175 kernel_add_lsp (zebra_lsp_t
*lsp
)
177 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
180 return kernel_lsp_cmd (RTM_ADD
, lsp
);
184 kernel_upd_lsp (zebra_lsp_t
*lsp
)
186 if (!lsp
|| !lsp
->best_nhlfe
) // unexpected
189 return kernel_lsp_cmd (RTM_CHANGE
, lsp
);
193 kernel_del_lsp (zebra_lsp_t
*lsp
)
195 if (!lsp
) // unexpected
198 return kernel_lsp_cmd (RTM_DELETE
, lsp
);
201 #define MAX_RTSOCK_BUF 128 * 1024
203 mpls_kernel_init (void)
205 int rcvbuf
, default_rcvbuf
;
208 if ((kr_state
.fd
= socket(AF_ROUTE
, SOCK_RAW
, 0)) == -1) {
209 zlog_warn("%s: socket", __func__
);
213 /* grow receive buffer, don't wanna miss messages */
214 optlen
= sizeof (default_rcvbuf
);
215 if (getsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
,
216 &default_rcvbuf
, &optlen
) == -1)
217 zlog_warn("kr_init getsockopt SOL_SOCKET SO_RCVBUF");
219 for (rcvbuf
= MAX_RTSOCK_BUF
;
220 rcvbuf
> default_rcvbuf
&&
221 setsockopt(kr_state
.fd
, SOL_SOCKET
, SO_RCVBUF
,
222 &rcvbuf
, sizeof (rcvbuf
)) == -1 && errno
== ENOBUFS
;