]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_mpls_openbsd.c
Merge branch 'vtysh-grammar'
[mirror_frr.git] / zebra / zebra_mpls_openbsd.c
1 /*
2 * Copyright (C) 2016 by Open Source Routing.
3 *
4 * This file is part of GNU Zebra.
5 *
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
9 * later version.
10 *
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.
15 *
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
19 * 02111-1307, USA.
20 */
21
22 #include <zebra.h>
23 #include <netmpls/mpls.h>
24 #include "zebra/rt.h"
25 #include "zebra/zebra_mpls.h"
26 #include "zebra/debug.h"
27
28 #include "privs.h"
29 #include "prefix.h"
30 #include "interface.h"
31 #include "log.h"
32
33 extern struct zebra_privs_t zserv_privs;
34
35 struct {
36 u_int32_t rtseq;
37 int fd;
38 } kr_state;
39
40 static int
41 kernel_send_rtmsg (int action, mpls_label_t in_label, zebra_nhlfe_t *nhlfe)
42 {
43 struct iovec iov[5];
44 struct rt_msghdr hdr;
45 struct sockaddr_mpls sa_label_in, sa_label_out;
46 struct sockaddr_in nexthop;
47 int iovcnt = 0;
48 int ret;
49
50 if (IS_ZEBRA_DEBUG_KERNEL)
51 zlog_debug ("kernel_send_rtmsg: 0x%x, label=%u", action, in_label);
52
53 /* initialize header */
54 bzero(&hdr, sizeof (hdr));
55 hdr.rtm_version = RTM_VERSION;
56
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);
63 hdr.rtm_priority = 0;
64 /* adjust iovec */
65 iov[iovcnt].iov_base = &hdr;
66 iov[iovcnt++].iov_len = sizeof (hdr);
67
68 /* in label */
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);
73 /* adjust header */
74 hdr.rtm_flags |= RTF_MPLS | RTF_MPATH;
75 hdr.rtm_addrs |= RTA_DST;
76 hdr.rtm_msglen += sizeof (sa_label_in);
77 /* adjust iovec */
78 iov[iovcnt].iov_base = &sa_label_in;
79 iov[iovcnt++].iov_len = sizeof (sa_label_in);
80
81 /* nexthop */
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;
86 /* adjust header */
87 hdr.rtm_flags |= RTF_GATEWAY;
88 hdr.rtm_addrs |= RTA_GATEWAY;
89 hdr.rtm_msglen += sizeof (nexthop);
90 /* adjust iovec */
91 iov[iovcnt].iov_base = &nexthop;
92 iov[iovcnt++].iov_len = sizeof (nexthop);
93
94 /* If action is RTM_DELETE we have to get rid of MPLS infos */
95 if (action != RTM_DELETE)
96 {
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);
102 /* adjust header */
103 hdr.rtm_addrs |= RTA_SRC;
104 hdr.rtm_flags |= RTF_MPLS;
105 hdr.rtm_msglen += sizeof (sa_label_out);
106 /* adjust iovec */
107 iov[iovcnt].iov_base = &sa_label_out;
108 iov[iovcnt++].iov_len = sizeof (sa_label_out);
109
110 if (nhlfe->nexthop->nh_label->label[0] == MPLS_LABEL_IMPLNULL)
111 hdr.rtm_mpls = MPLS_OP_POP;
112 else
113 hdr.rtm_mpls = MPLS_OP_SWAP;
114 }
115
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");
121
122 if (ret == -1)
123 zlog_err ("kernel_send_rtmsg: %s", safe_strerror (errno));
124
125 return ret;
126 }
127
128 static int
129 kernel_lsp_cmd (int action, zebra_lsp_t *lsp)
130 {
131 zebra_nhlfe_t *nhlfe;
132 struct nexthop *nexthop = NULL;
133 int nexthop_num = 0;
134
135 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
136 {
137 nexthop = nhlfe->nexthop;
138 if (!nexthop)
139 continue;
140
141 if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM)
142 break;
143
144 /* XXX */
145 if (NHLFE_FAMILY(nhlfe) == AF_INET6)
146 continue;
147
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))))
154 {
155 nexthop_num++;
156
157 kernel_send_rtmsg (action, lsp->ile.in_label, nhlfe);
158 if (action == RTM_ADD || action == RTM_CHANGE)
159 {
160 SET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
161 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
162 }
163 else
164 {
165 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
166 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
167 }
168 }
169 }
170
171 return (0);
172 }
173
174 int
175 kernel_add_lsp (zebra_lsp_t *lsp)
176 {
177 if (!lsp || !lsp->best_nhlfe) // unexpected
178 return -1;
179
180 return kernel_lsp_cmd (RTM_ADD, lsp);
181 }
182
183 int
184 kernel_upd_lsp (zebra_lsp_t *lsp)
185 {
186 if (!lsp || !lsp->best_nhlfe) // unexpected
187 return -1;
188
189 return kernel_lsp_cmd (RTM_CHANGE, lsp);
190 }
191
192 int
193 kernel_del_lsp (zebra_lsp_t *lsp)
194 {
195 if (!lsp) // unexpected
196 return -1;
197
198 return kernel_lsp_cmd (RTM_DELETE, lsp);
199 }
200
201 #define MAX_RTSOCK_BUF 128 * 1024
202 int
203 mpls_kernel_init (void)
204 {
205 int rcvbuf, default_rcvbuf;
206 socklen_t optlen;
207
208 if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
209 zlog_warn("%s: socket", __func__);
210 return -1;
211 }
212
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");
218 else
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;
223 rcvbuf /= 2)
224 ; /* nothing */
225
226 kr_state.rtseq = 1;
227
228 return 0;
229 }