/* Interface between zebra message and rtm message. */
static int kernel_rtm_ipv4(int cmd, const struct prefix *p,
- struct route_entry *re)
+ const struct nexthop_group *ng, uint32_t metric)
{
struct sockaddr_in *mask = NULL;
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
/* Make gateway. */
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
* other than ADD and DELETE?
*/
if ((cmd == RTM_ADD && NEXTHOP_IS_ACTIVE(nexthop->flags))
- || (cmd == RTM_DELETE
- && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))) {
+ || (cmd == RTM_DELETE)) {
if (nexthop->type == NEXTHOP_TYPE_IPV4
|| nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
sin_gate.sin_addr = nexthop->gate.ipv4;
(union sockunion *)mask,
gate ? (union sockunion *)&sin_gate
: NULL,
- smplsp, ifindex, bh_type, re->metric);
+ smplsp, ifindex, bh_type, metric);
if (IS_ZEBRA_DEBUG_RIB) {
if (!gate) {
zlog_debug(
- "%s: %s: attention! gate not found for re %p",
- __func__, prefix_buf, re);
- route_entry_dump(p, NULL, re);
+ "%s: %s: attention! gate not found for re",
+ __func__, prefix_buf);
} else
inet_ntop(AF_INET, &sin_gate.sin_addr,
gate_buf, INET_ADDRSTRLEN);
/* 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 entry %p",
- __func__, re);
+ zlog_debug("%s: No useful nexthops were found in RIB prefix %s",
+ __func__, prefix2str(p, prefix_buf,
+ sizeof(prefix_buf)));
return 1;
}
/* Interface between zebra message and rtm message. */
static int kernel_rtm_ipv6(int cmd, const struct prefix *p,
- struct route_entry *re)
+ const struct nexthop_group *ng, uint32_t metric)
{
struct sockaddr_in6 *mask;
struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
/* Make gateway. */
- for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ for (ALL_NEXTHOPS_PTR(ng, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;
error = rtm_write(cmd, (union sockunion *)&sin_dest,
(union sockunion *)mask,
gate ? (union sockunion *)&sin_gate : NULL,
- smplsp, ifindex, bh_type, re->metric);
+ smplsp, ifindex, bh_type, metric);
(void)error;
nexthop_num++;
return 0; /*XXX*/
}
-static int kernel_rtm(int cmd, const struct prefix *p, struct route_entry *re)
+static int kernel_rtm(int cmd, const struct prefix *p,
+ const struct nexthop_group *ng, uint32_t metric)
{
switch (PREFIX_FAMILY(p)) {
case AF_INET:
- return kernel_rtm_ipv4(cmd, p, re);
+ return kernel_rtm_ipv4(cmd, p, ng, metric);
case AF_INET6:
- return kernel_rtm_ipv6(cmd, p, re);
+ return kernel_rtm_ipv6(cmd, p, ng, metric);
}
return 0;
}
+/*
+ * Update or delete a prefix from the kernel,
+ * using info from a dataplane context struct.
+ */
+enum zebra_dplane_result kernel_route_update(dplane_ctx_h ctx)
+{
+ enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ if (dplane_ctx_get_src(ctx) != NULL) {
+ zlog_err("route add: IPv6 sourcedest routes unsupported!");
+ res = ZEBRA_DPLANE_REQUEST_FAILURE;
+ goto done;
+ }
+
+ if (zserv_privs.change(ZPRIVS_RAISE))
+ zlog_err("Can't raise privileges");
+
+ if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE)
+ 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)
+ 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
+ */
+ kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx),
+ dplane_ctx_get_old_ng(ctx),
+ dplane_ctx_get_old_metric(ctx));
+
+ 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 %u",
+ dplane_ctx_get_op(ctx));
+ res = ZEBRA_DPLANE_REQUEST_FAILURE;
+ }
+
+ if (zserv_privs.change(ZPRIVS_LOWER))
+ zlog_err("Can't lower privileges");
+
+done:
+
+ return res;
+}
+
enum zebra_dplane_result kernel_route_rib(struct route_node *rn,
const struct prefix *p,
const struct prefix *src_p,
}
frr_elevate_privs(&zserv_privs) {
-
if (old)
- route |= kernel_rtm(RTM_DELETE, p, old);
-
+ route |= kernel_rtm(RTM_DELETE, p,
+ &old->ng, old->metric);
if (new)
- route |= kernel_rtm(RTM_ADD, p, new);
-
+ route |= kernel_rtm(RTM_ADD, p, &new->ng, new->metric);
}
if (new) {
return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
-enum zebra_dplane_result kernel_route_update(dplane_ctx_h ctx)
-{
- return ZEBRA_DPLANE_REQUEST_FAILURE;
-}
-
int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
int llalen, ns_id_t ns_id)
{
route_tag_t zd_tag;
route_tag_t zd_old_tag;
uint32_t zd_metric;
+ uint32_t zd_old_metric;
uint16_t zd_instance;
uint16_t zd_old_instance;
/* Nexthops */
struct nexthop_group zd_ng;
+ /* "Previous" nexthops, used only in route update case without netlink */
+ struct nexthop_group zd_old_ng;
+
/* TODO -- use fixed array of nexthops, to avoid mallocs? */
/* Embedded list linkage */
nexthops_free((*pctx)->zd_ng.nexthop);
}
+ if ((*pctx)->zd_old_ng.nexthop) {
+ nexthops_free((*pctx)->zd_old_ng.nexthop);
+ }
+
/* Clear validation value */
(*pctx)->zd_magic = 0;
return ctx->zd_metric;
}
+uint32_t dplane_ctx_get_old_metric(const dplane_ctx_h ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->zd_old_metric;
+}
+
uint32_t dplane_ctx_get_mtu(const dplane_ctx_h ctx)
{
DPLANE_CTX_VALID(ctx);
return &(ctx->zd_ng);
}
+const struct nexthop_group *dplane_ctx_get_old_ng(const dplane_ctx_h ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->zd_old_ng);
+}
+
const struct zebra_dplane_info *dplane_ctx_get_ns(const dplane_ctx_h ctx)
{
DPLANE_CTX_VALID(ctx);
ctx->zd_table_id = re->table;
ctx->zd_metric = re->metric;
+ ctx->zd_old_metric = re->metric;
ctx->zd_vrf_id = re->vrf_id;
ctx->zd_mtu = re->mtu;
ctx->zd_nexthop_mtu = re->nexthop_mtu;
ctx->zd_old_type = old_re->type;
ctx->zd_old_instance = old_re->instance;
ctx->zd_old_distance = old_re->distance;
+ ctx->zd_old_metric = old_re->metric;
+
+#ifndef HAVE_NETLINK
+ /* Capture previous re's nexthops too for bsd, sigh */
+ copy_nexthops(&(ctx->zd_old_ng.nexthop),
+ old_re->ng.nexthop, NULL);
+#endif /* !HAVE_NETLINK */
}
/* Enqueue context for processing */