1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
|
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Kernel routing table updates by routing socket.
* Copyright (C) 1997, 98 Kunihiro Ishiguro
*/
#include <zebra.h>
#include <net/route.h>
#ifndef HAVE_NETLINK
#ifdef __OpenBSD__
#include <netmpls/mpls.h>
#endif
#include "if.h"
#include "prefix.h"
#include "sockunion.h"
#include "log.h"
#include "privs.h"
#include "vxlan.h"
#include "lib_errors.h"
#include "zebra/debug.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
#include "zebra/kernel_socket.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_errors.h"
extern struct zebra_privs_t zserv_privs;
#ifdef __OpenBSD__
static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label,
struct sockaddr_mpls *smpls)
{
if (nh_label->num_labels > 1) {
flog_warn(EC_ZEBRA_MAX_LABELS_PUSH,
"%s: can't push %u labels at once (maximum is 1)",
__func__, nh_label->num_labels);
return -1;
}
memset(smpls, 0, sizeof(*smpls));
smpls->smpls_len = sizeof(*smpls);
smpls->smpls_family = AF_MPLS;
smpls->smpls_label = htonl(nh_label->label[0] << MPLS_LABEL_OFFSET);
return 0;
}
#endif
/* Interface between zebra message and rtm message. */
static int kernel_rtm(int cmd, const struct prefix *p,
const struct nexthop_group *ng, uint32_t metric)
{
union sockunion sin_dest, sin_mask, sin_gate;
#ifdef __OpenBSD__
struct sockaddr_mpls smpls;
#endif
union sockunion *smplsp = NULL;
struct nexthop *nexthop;
int nexthop_num = 0;
ifindex_t ifindex = 0;
bool gate = false;
int error;
char gate_buf[INET6_BUFSIZ];
enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
/*
* We only have the ability to ADD or DELETE at this point
* in time.
*/
if (cmd != RTM_ADD && cmd != RTM_DELETE) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %pFX odd command %s", __func__, p,
lookup_msg(rtm_type_str, cmd, NULL));
return 0;
}
memset(&sin_dest, 0, sizeof(sin_dest));
memset(&sin_gate, 0, sizeof(sin_gate));
memset(&sin_mask, 0, sizeof(sin_mask));
switch (p->family) {
case AF_INET:
sin_dest.sin.sin_family = AF_INET;
sin_dest.sin.sin_addr = p->u.prefix4;
sin_gate.sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin_dest.sin.sin_len = sizeof(struct sockaddr_in);
sin_gate.sin.sin_len = sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
break;
case AF_INET6:
sin_dest.sin6.sin6_family = AF_INET6;
sin_dest.sin6.sin6_addr = p->u.prefix6;
sin_gate.sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin_dest.sin6.sin6_len = sizeof(struct sockaddr_in6);
sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
break;
}
/* Make gateway. */
for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
/*
* We only want to use the actual good nexthops
*/
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ||
!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
continue;
smplsp = NULL;
gate = false;
snprintf(gate_buf, sizeof(gate_buf), "NULL");
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
sin_gate.sin.sin_addr = nexthop->gate.ipv4;
sin_gate.sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin_gate.sin.sin_len = sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
ifindex = nexthop->ifindex;
gate = true;
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
sin_gate.sin6.sin6_addr = nexthop->gate.ipv6;
sin_gate.sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin_gate.sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
ifindex = nexthop->ifindex;
/* Under kame set interface index to link local address */
if (IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6.sin6_addr))
SET_IN6_LINKLOCAL_IFINDEX(sin_gate.sin6.sin6_addr, ifindex);
gate = true;
break;
case NEXTHOP_TYPE_IFINDEX:
ifindex = nexthop->ifindex;
break;
case NEXTHOP_TYPE_BLACKHOLE:
bh_type = nexthop->bh_type;
switch (p->family) {
case AF_INET: {
struct in_addr loopback;
loopback.s_addr = htonl(INADDR_LOOPBACK);
sin_gate.sin.sin_addr = loopback;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin_gate.sin.sin_len =
sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
gate = true;
} break;
case AF_INET6: {
struct in6_addr loopback;
inet_pton(AF_INET6, "::1", &loopback);
sin_gate.sin6.sin6_addr = loopback;
sin_gate.sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCTSOCKADDR_SA_LEN
sin_gate.sin6.sin6_len =
sizeof(struct sockaddr_in6);
#endif /* HAVE_STRUCTSOCKADDR_SA_LEN */
gate = true;
} break;
}
}
switch (p->family) {
case AF_INET:
masklen2ip(p->prefixlen, &sin_mask.sin.sin_addr);
sin_mask.sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin_mask.sin.sin_len = sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
break;
case AF_INET6:
masklen2ip6(p->prefixlen, &sin_mask.sin6.sin6_addr);
sin_mask.sin6.sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin_mask.sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
break;
}
#ifdef __OpenBSD__
if (nexthop->nh_label) {
if (kernel_rtm_add_labels(nexthop->nh_label,
&smpls) != 0)
continue;
smplsp = (union sockunion *)&smpls;
}
#endif
error = rtm_write(cmd, &sin_dest, &sin_mask,
gate ? &sin_gate : NULL, smplsp,
ifindex, bh_type, metric);
if (IS_ZEBRA_DEBUG_KERNEL) {
if (!gate) {
zlog_debug(
"%s: %pFX: attention! gate not found for re",
__func__, p);
} else {
switch (p->family) {
case AF_INET:
inet_ntop(AF_INET,
&sin_gate.sin.sin_addr,
gate_buf, sizeof(gate_buf));
break;
case AF_INET6:
inet_ntop(AF_INET6,
&sin_gate.sin6.sin6_addr,
gate_buf, sizeof(gate_buf));
break;
default:
snprintf(gate_buf, sizeof(gate_buf),
"(invalid-af)");
break;
}
}
}
switch (error) {
/* We only flag nexthops as being in FIB if
* rtm_write() did its work. */
case ZEBRA_ERR_NOERROR:
nexthop_num++;
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %pFX: successfully did NH %s",
__func__, p, gate_buf);
if (cmd == RTM_ADD)
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
break;
/* The only valid case for this error is
* kernel's failure to install a multipath
* route, which is common for FreeBSD. This
* should be ignored silently, but logged as an error
* otherwise.
*/
case ZEBRA_ERR_RTEXIST:
if (cmd != RTM_ADD)
flog_err(EC_LIB_SYSTEM_CALL,
"%s: rtm_write() returned %d for command %d",
__func__, error, cmd);
continue;
/* Note any unexpected status returns */
case ZEBRA_ERR_RTNOEXIST:
if (cmd != RTM_DELETE)
flog_err(EC_LIB_SYSTEM_CALL,
"%s: rtm_write() returned %d for command %d",
__func__, error, cmd);
break;
default:
flog_err(
EC_LIB_SYSTEM_CALL,
"%s: %pFX: rtm_write() unexpectedly returned %d for command %s",
__func__, p, error,
lookup_msg(rtm_type_str, cmd, NULL));
break;
}
} /* for (ALL_NEXTHOPS(...))*/
/* If there was no useful nexthop, then complain. */
if (nexthop_num == 0) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"%s: No useful nexthops were found in RIB prefix %pFX",
__func__, p);
return 1;
}
return 0; /*XXX*/
}
/*
* Update or delete a prefix from the kernel,
* using info from a dataplane context struct.
*/
enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
{
enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
uint32_t type, old_type;
if (dplane_ctx_get_src(ctx) != NULL) {
zlog_err("route add: IPv6 sourcedest routes unsupported!");
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
type = dplane_ctx_get_type(ctx);
old_type = dplane_ctx_get_old_type(ctx);
frr_with_privs(&zserv_privs) {
if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST)
kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
dplane_ctx_get_ng(ctx),
dplane_ctx_get_metric(ctx));
} else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST)
kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
dplane_ctx_get_ng(ctx),
dplane_ctx_get_metric(ctx));
} else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
/* Must do delete and add separately -
* no update available
*/
if (!RSYSTEM_ROUTE(old_type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST)
kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
dplane_ctx_get_old_ng(ctx),
dplane_ctx_get_old_metric(ctx));
if (!RSYSTEM_ROUTE(type) && dplane_ctx_get_safi(ctx) != SAFI_MULTICAST)
kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx),
dplane_ctx_get_ng(ctx),
dplane_ctx_get_metric(ctx));
} else {
zlog_err("Invalid routing socket update op %s (%u)",
dplane_op2str(dplane_ctx_get_op(ctx)),
dplane_ctx_get_op(ctx));
res = ZEBRA_DPLANE_REQUEST_FAILURE;
}
} /* Elevated privs */
return res;
}
enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
{
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, bool reg)
{
/* TODO */
return 0;
}
int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen,
ns_id_t ns_id, uint8_t family, bool permanent)
{
/* TODO */
return 0;
}
/* NYI on routing-socket platforms, but we've always returned 'success'... */
enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
{
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute)
{
return 0;
}
/*
* Update MAC, using dataplane context object. No-op here for now.
*/
enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx)
{
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
extern int kernel_interface_set_master(struct interface *master,
struct interface *slave)
{
return 0;
}
uint32_t kernel_get_speed(struct interface *ifp, int *error)
{
return ifp->speed;
}
int kernel_upd_mac_nh(uint32_t nh_id, struct in_addr vtep_ip)
{
return 0;
}
int kernel_del_mac_nh(uint32_t nh_id)
{
return 0;
}
int kernel_upd_mac_nhg(uint32_t nhg_id, uint32_t nh_cnt,
struct nh_grp *nh_ids)
{
return 0;
}
int kernel_del_mac_nhg(uint32_t nhg_id)
{
return 0;
}
#endif /* !HAVE_NETLINK */
|