]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rt_socket.c
zebra: CLI commands to display ethernet segments
[mirror_frr.git] / zebra / rt_socket.c
CommitLineData
718e3744 1/*
2 * Kernel routing table updates by routing socket.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
896014f4
DL
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718e3744 20 */
21
22#include <zebra.h>
ddfeb486
DL
23
24#ifndef HAVE_NETLINK
25
fe6c7157 26#ifdef __OpenBSD__
d3e2c74a
RW
27#include <netmpls/mpls.h>
28#endif
718e3744 29
30#include "if.h"
31#include "prefix.h"
32#include "sockunion.h"
33#include "log.h"
edd7c245 34#include "privs.h"
13d60d35 35#include "vxlan.h"
174482ef 36#include "lib_errors.h"
718e3744 37
38#include "zebra/debug.h"
39#include "zebra/rib.h"
6621ca86 40#include "zebra/rt.h"
dc95824a 41#include "zebra/kernel_socket.h"
d3e2c74a 42#include "zebra/zebra_mpls.h"
364fed6b 43#include "zebra/zebra_errors.h"
718e3744 44
edd7c245 45extern struct zebra_privs_t zserv_privs;
46
5e8c8947 47#ifdef __OpenBSD__
8ecdb26e 48static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label,
5e8c8947
RW
49 struct sockaddr_mpls *smpls)
50{
51 if (nh_label->num_labels > 1) {
e914ccbe 52 flog_warn(EC_ZEBRA_MAX_LABELS_PUSH,
3efd0893 53 "%s: can't push %u labels at once (maximum is 1)",
9df414fe 54 __func__, nh_label->num_labels);
5e8c8947
RW
55 return -1;
56 }
57
58 memset(smpls, 0, sizeof(*smpls));
59 smpls->smpls_len = sizeof(*smpls);
60 smpls->smpls_family = AF_MPLS;
61 smpls->smpls_label = htonl(nh_label->label[0] << MPLS_LABEL_OFFSET);
62
63 return 0;
64}
65#endif
66
718e3744 67/* Interface between zebra message and rtm message. */
08ea27d1
DS
68static int kernel_rtm(int cmd, const struct prefix *p,
69 const struct nexthop_group *ng, uint32_t metric)
718e3744 70
71{
ca2c70bd 72 union sockunion sin_dest, sin_mask, sin_gate;
fe6c7157 73#ifdef __OpenBSD__
d62a17ae 74 struct sockaddr_mpls smpls;
d3e2c74a 75#endif
d62a17ae 76 union sockunion *smplsp = NULL;
77 struct nexthop *nexthop;
78 int nexthop_num = 0;
79 ifindex_t ifindex = 0;
4dd39a0e 80 bool gate = false;
d62a17ae 81 int error;
981dc13f 82 char gate_buf[INET6_BUFSIZ];
d62a17ae 83 char prefix_buf[PREFIX_STRLEN];
a8309422 84 enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
d62a17ae 85
683c06ad 86 prefix2str(p, prefix_buf, sizeof(prefix_buf));
718e3744 87
86afd529
DS
88 /*
89 * We only have the ability to ADD or DELETE at this point
90 * in time.
91 */
92 if (cmd != RTM_ADD && cmd != RTM_DELETE) {
93 if (IS_ZEBRA_DEBUG_KERNEL)
5ea8213f 94 zlog_debug("%s: %s odd command %s",
86afd529 95 __func__, prefix_buf,
5ea8213f 96 lookup_msg(rtm_type_str, cmd, NULL));
86afd529
DS
97 return 0;
98 }
99
08ea27d1
DS
100 memset(&sin_dest, 0, sizeof(sin_dest));
101 memset(&sin_gate, 0, sizeof(sin_gate));
ca2c70bd 102 memset(&sin_mask, 0, sizeof(sin_mask));
718e3744 103
08ea27d1
DS
104 switch (p->family) {
105 case AF_INET:
106 sin_dest.sin.sin_family = AF_INET;
08ea27d1
DS
107 sin_dest.sin.sin_addr = p->u.prefix4;
108 sin_gate.sin.sin_family = AF_INET;
0413dd75
RZ
109#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
110 sin_dest.sin.sin_len = sizeof(struct sockaddr_in);
111 sin_gate.sin.sin_len = sizeof(struct sockaddr_in);
112#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
08ea27d1
DS
113 break;
114 case AF_INET6:
115 sin_dest.sin6.sin6_family = AF_INET6;
08ea27d1
DS
116 sin_dest.sin6.sin6_addr = p->u.prefix6;
117 sin_gate.sin6.sin6_family = AF_INET6;
0413dd75
RZ
118#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
119 sin_dest.sin6.sin6_len = sizeof(struct sockaddr_in6);
120 sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6);
121#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
08ea27d1
DS
122 break;
123 }
718e3744 124
d62a17ae 125 /* Make gateway. */
01ce7cba 126 for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
86afd529
DS
127 /*
128 * We only want to use the actual good nexthops
129 */
130 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ||
131 !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
d62a17ae 132 continue;
133
c2519893 134 smplsp = NULL;
4dd39a0e 135 gate = false;
981dc13f 136 snprintf(gate_buf, sizeof(gate_buf), "NULL");
d62a17ae 137
86afd529
DS
138 switch (nexthop->type) {
139 case NEXTHOP_TYPE_IPV4:
140 case NEXTHOP_TYPE_IPV4_IFINDEX:
141 sin_gate.sin.sin_addr = nexthop->gate.ipv4;
142 sin_gate.sin.sin_family = AF_INET;
0413dd75
RZ
143#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
144 sin_gate.sin.sin_len = sizeof(struct sockaddr_in);
145#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
86afd529 146 ifindex = nexthop->ifindex;
4dd39a0e 147 gate = true;
86afd529
DS
148 break;
149 case NEXTHOP_TYPE_IPV6:
150 case NEXTHOP_TYPE_IPV6_IFINDEX:
151 sin_gate.sin6.sin6_addr = nexthop->gate.ipv6;
152 sin_gate.sin6.sin6_family = AF_INET6;
0413dd75
RZ
153#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
154 sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6);
155#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
86afd529 156 ifindex = nexthop->ifindex;
08ea27d1
DS
157/* Under kame set interface index to link local address */
158#ifdef KAME
159
160#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
c9277ebb
DS
161 do { \
162 (a).s6_addr[2] = ((i) >> 8) & 0xff; \
163 (a).s6_addr[3] = (i)&0xff; \
164 } while (0)
08ea27d1 165
86afd529
DS
166 if (IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6.sin6_addr))
167 SET_IN6_LINKLOCAL_IFINDEX(
168 sin_gate.sin6.sin6_addr,
169 ifindex);
08ea27d1
DS
170#endif /* KAME */
171
4dd39a0e 172 gate = true;
86afd529
DS
173 break;
174 case NEXTHOP_TYPE_IFINDEX:
175 ifindex = nexthop->ifindex;
176 break;
177 case NEXTHOP_TYPE_BLACKHOLE:
178 bh_type = nexthop->bh_type;
179 switch (p->family) {
c3d6b386 180 case AF_INET: {
86afd529 181 struct in_addr loopback;
381477e8 182
86afd529
DS
183 loopback.s_addr = htonl(INADDR_LOOPBACK);
184 sin_gate.sin.sin_addr = loopback;
0413dd75
RZ
185#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
186 sin_gate.sin.sin_len =
187 sizeof(struct sockaddr_in);
188#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
4dd39a0e 189 gate = true;
381477e8
DS
190 } break;
191 case AF_INET6: {
192 struct in6_addr loopback;
193
194 inet_pton(AF_INET6, "::1", &loopback);
195
196 sin_gate.sin6.sin6_addr = loopback;
197 sin_gate.sin6.sin6_family = AF_INET6;
198
199#ifdef HAVE_STRUCTSOCKADDR_SA_LEN
200 sin_gate.sin6.sin6_len =
201 sizeof(struct sockaddr_in6);
202#endif /* HAVE_STRUCTSOCKADDR_SA_LEN */
203 gate = true;
204 } break;
d62a17ae 205 }
86afd529
DS
206 }
207
208 switch (p->family) {
209 case AF_INET:
18d10d88
DS
210 masklen2ip(p->prefixlen, &sin_mask.sin.sin_addr);
211 sin_mask.sin.sin_family = AF_INET;
0413dd75
RZ
212#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
213 sin_mask.sin.sin_len = sizeof(struct sockaddr_in);
214#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
86afd529
DS
215 break;
216 case AF_INET6:
18d10d88
DS
217 masklen2ip6(p->prefixlen, &sin_mask.sin6.sin6_addr);
218 sin_mask.sin6.sin6_family = AF_INET6;
0413dd75
RZ
219#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
220 sin_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
221#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
86afd529
DS
222 break;
223 }
718e3744 224
fe6c7157 225#ifdef __OpenBSD__
b24204be
MS
226 if (nexthop->nh_label) {
227 if (kernel_rtm_add_labels(nexthop->nh_label,
228 &smpls) != 0)
229 continue;
230 smplsp = (union sockunion *)&smpls;
231 }
d3e2c74a 232#endif
18d10d88 233 error = rtm_write(cmd, &sin_dest, &sin_mask,
86afd529
DS
234 gate ? &sin_gate : NULL, smplsp,
235 ifindex, bh_type, metric);
236
237 if (IS_ZEBRA_DEBUG_KERNEL) {
238 if (!gate) {
981dc13f
RZ
239 zlog_debug(
240 "%s: %s: attention! gate not found for re",
241 __func__, prefix_buf);
242 } else {
243 switch (p->family) {
c3d6b386 244 case AF_INET:
981dc13f
RZ
245 inet_ntop(AF_INET,
246 &sin_gate.sin.sin_addr,
247 gate_buf, sizeof(gate_buf));
248 break;
249
c3d6b386 250 case AF_INET6:
981dc13f
RZ
251 inet_ntop(AF_INET6,
252 &sin_gate.sin6.sin6_addr,
253 gate_buf, sizeof(gate_buf));
254 break;
255
256 default:
257 snprintf(gate_buf, sizeof(gate_buf),
258 "(invalid-af)");
259 break;
260 }
261 }
86afd529
DS
262 }
263 switch (error) {
264 /* We only flag nexthops as being in FIB if
265 * rtm_write() did its work. */
266 case ZEBRA_ERR_NOERROR:
267 nexthop_num++;
268 if (IS_ZEBRA_DEBUG_KERNEL)
269 zlog_debug("%s: %s: successfully did NH %s",
270 __func__, prefix_buf, gate_buf);
271 if (cmd == RTM_ADD)
272 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
273 break;
274
275 /* The only valid case for this error is
276 * kernel's failure to install a multipath
277 * route, which is common for FreeBSD. This
278 * should be ignored silently, but logged as an error
279 * otherwise.
280 */
281 case ZEBRA_ERR_RTEXIST:
282 if (cmd != RTM_ADD)
283 flog_err(EC_LIB_SYSTEM_CALL,
284 "%s: rtm_write() returned %d for command %d",
285 __func__, error, cmd);
286 continue;
d62a17ae 287
86afd529
DS
288 /* Note any unexpected status returns */
289 default:
31be7dbb
RZ
290 flog_err(
291 EC_LIB_SYSTEM_CALL,
292 "%s: %s: rtm_write() unexpectedly returned %d for command %s",
293 __func__, prefix_buf, error,
294 lookup_msg(rtm_type_str, cmd, NULL));
86afd529
DS
295 break;
296 }
d62a17ae 297 } /* for (ALL_NEXTHOPS(...))*/
298
299 /* If there was no useful nexthop, then complain. */
560e3136
DS
300 if (nexthop_num == 0) {
301 if (IS_ZEBRA_DEBUG_KERNEL)
31be7dbb
RZ
302 zlog_debug(
303 "%s: No useful nexthops were found in RIB prefix %s",
304 __func__, prefix_buf);
560e3136
DS
305 return 1;
306 }
d62a17ae 307
308 return 0; /*XXX*/
718e3744 309}
310
01ce7cba
MS
311/*
312 * Update or delete a prefix from the kernel,
313 * using info from a dataplane context struct.
314 */
25779064 315enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
01ce7cba
MS
316{
317 enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
3cdba47a 318 uint32_t type, old_type;
01ce7cba
MS
319
320 if (dplane_ctx_get_src(ctx) != NULL) {
321 zlog_err("route add: IPv6 sourcedest routes unsupported!");
e677d109 322 return ZEBRA_DPLANE_REQUEST_FAILURE;
01ce7cba
MS
323 }
324
3cdba47a
DS
325 type = dplane_ctx_get_type(ctx);
326 old_type = dplane_ctx_get_old_type(ctx);
327
0cf6db21 328 frr_with_privs(&zserv_privs) {
f183e380 329
3cdba47a
DS
330 if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
331 if (!RSYSTEM_ROUTE(type))
332 kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
333 dplane_ctx_get_ng(ctx),
334 dplane_ctx_get_metric(ctx));
335 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
336 if (!RSYSTEM_ROUTE(type))
337 kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
338 dplane_ctx_get_ng(ctx),
339 dplane_ctx_get_metric(ctx));
340 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
f183e380
MS
341 /* Must do delete and add separately -
342 * no update available
343 */
3cdba47a
DS
344 if (!RSYSTEM_ROUTE(old_type))
345 kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
346 dplane_ctx_get_old_ng(ctx),
347 dplane_ctx_get_old_metric(ctx));
348
349 if (!RSYSTEM_ROUTE(type))
350 kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
351 dplane_ctx_get_ng(ctx),
352 dplane_ctx_get_metric(ctx));
f183e380
MS
353 } else {
354 zlog_err("Invalid routing socket update op %s (%u)",
355 dplane_op2str(dplane_ctx_get_op(ctx)),
356 dplane_ctx_get_op(ctx));
357 res = ZEBRA_DPLANE_REQUEST_FAILURE;
358 }
359 } /* Elevated privs */
01ce7cba 360
3cdba47a
DS
361 if (RSYSTEM_ROUTE(type)
362 && dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE) {
363 struct nexthop *nexthop;
364
365 for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
366 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
367 continue;
368
369 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
370 SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
371 }
372 }
373 }
374
01ce7cba
MS
375 return res;
376}
377
07cc1745
SW
378enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
379{
380 return ZEBRA_DPLANE_REQUEST_SUCCESS;
381}
382
d62a17ae 383int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
5895d33f 384 int llalen, ns_id_t ns_id)
6b8a5694 385{
d62a17ae 386 /* TODO */
387 return 0;
6b8a5694 388}
1498c059 389
931fa60c
MS
390/* NYI on routing-socket platforms, but we've always returned 'success'... */
391enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
392{
393 return ZEBRA_DPLANE_REQUEST_SUCCESS;
394}
395
43b5cc5e 396extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute)
1498c059 397{
d62a17ae 398 return 0;
1498c059 399}
13d60d35 400
036d93c0
MS
401/*
402 * Update MAC, using dataplane context object. No-op here for now.
403 */
404enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
2232a77c 405{
036d93c0 406 return ZEBRA_DPLANE_REQUEST_SUCCESS;
2232a77c 407}
408
e0ae31b8
DS
409extern int kernel_interface_set_master(struct interface *master,
410 struct interface *slave)
411{
412 return 0;
413}
0ecfe5bf 414
594c2878 415uint32_t kernel_get_speed(struct interface *ifp, int *error)
dc7b3cae
DS
416{
417 return ifp->speed;
418}
419
ddfeb486 420#endif /* !HAVE_NETLINK */