diff options
Diffstat (limited to 'zebra/rule_netlink.c')
| -rw-r--r-- | zebra/rule_netlink.c | 107 |
1 files changed, 59 insertions, 48 deletions
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index b7be398506..3a3baab4ca 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -58,10 +58,12 @@ * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer * or the number of bytes written to buf. */ -static ssize_t netlink_rule_msg_encode( - int cmd, const struct zebra_dplane_ctx *ctx, uint32_t filter_bm, - uint32_t priority, uint32_t table, const struct prefix *src_ip, - const struct prefix *dst_ip, uint32_t fwmark, void *buf, size_t buflen) +static ssize_t +netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx, + uint32_t filter_bm, uint32_t priority, uint32_t table, + const struct prefix *src_ip, + const struct prefix *dst_ip, uint32_t fwmark, + uint8_t dsfield, void *buf, size_t buflen) { uint8_t protocol = RTPROT_ZEBRA; int family; @@ -76,6 +78,8 @@ static ssize_t netlink_rule_msg_encode( char buf1[PREFIX_STRLEN]; char buf2[PREFIX_STRLEN]; + if (buflen < sizeof(*req)) + return 0; memset(req, 0, sizeof(*req)); family = PREFIX_FAMILY(src_ip); bytelen = (family == AF_INET ? 4 : 16); @@ -122,6 +126,10 @@ static ssize_t netlink_rule_msg_encode( return 0; } + /* dsfield, if specified */ + if (filter_bm & PBR_FILTER_DSFIELD) + req->frh.tos = dsfield; + /* Route table to use to forward, if filter criteria matches. */ if (table < 256) req->frh.table = table; @@ -142,53 +150,55 @@ static ssize_t netlink_rule_msg_encode( return NLMSG_ALIGN(req->n.nlmsg_len); } -/* Install or uninstall specified rule for a specific interface. - * Form netlink message and ship it. - */ -static int -netlink_rule_update_internal(int cmd, const struct zebra_dplane_ctx *ctx, - uint32_t filter_bm, uint32_t priority, - uint32_t table, const struct prefix *src_ip, - const struct prefix *dst_ip, uint32_t fwmark) +static ssize_t netlink_rule_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, + size_t buflen) { - char buf[NL_PKT_BUF_SIZE]; + int cmd = RTM_NEWRULE; + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_RULE_DELETE) + cmd = RTM_DELRULE; + + return netlink_rule_msg_encode( + cmd, ctx, dplane_ctx_rule_get_filter_bm(ctx), + dplane_ctx_rule_get_priority(ctx), + dplane_ctx_rule_get_table(ctx), dplane_ctx_rule_get_src_ip(ctx), + dplane_ctx_rule_get_dst_ip(ctx), + dplane_ctx_rule_get_fwmark(ctx), + dplane_ctx_rule_get_dsfield(ctx), buf, buflen); +} - netlink_rule_msg_encode(cmd, ctx, filter_bm, priority, table, src_ip, - dst_ip, fwmark, buf, sizeof(buf)); - return netlink_talk_info(netlink_talk_filter, (void *)&buf, - dplane_ctx_get_ns(ctx), 0); +static ssize_t netlink_oldrule_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + return netlink_rule_msg_encode( + RTM_DELRULE, ctx, dplane_ctx_rule_get_old_filter_bm(ctx), + dplane_ctx_rule_get_old_priority(ctx), + dplane_ctx_rule_get_old_table(ctx), + dplane_ctx_rule_get_old_src_ip(ctx), + dplane_ctx_rule_get_old_dst_ip(ctx), + dplane_ctx_rule_get_old_fwmark(ctx), + dplane_ctx_rule_get_old_dsfield(ctx), buf, buflen); } + /* Public functions */ -/* - * Add, update or delete a rule from the - * kernel, using info from a dataplane context. - */ -enum zebra_dplane_result kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx) +enum netlink_msg_status +netlink_put_rule_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) { enum dplane_op_e op; - int cmd; - int ret; + enum netlink_msg_status ret; op = dplane_ctx_get_op(ctx); - if (op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE) - cmd = RTM_NEWRULE; - else if (op == DPLANE_OP_RULE_DELETE) - cmd = RTM_DELRULE; - else { + if (!(op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE + || op == DPLANE_OP_RULE_DELETE)) { flog_err( EC_ZEBRA_PBR_RULE_UPDATE, "Context received for kernel rule update with incorrect OP code (%u)", op); - return ZEBRA_DPLANE_REQUEST_FAILURE; + return FRR_NETLINK_ERROR; } - ret = netlink_rule_update_internal( - cmd, ctx, dplane_ctx_rule_get_filter_bm(ctx), - dplane_ctx_rule_get_priority(ctx), - dplane_ctx_rule_get_table(ctx), dplane_ctx_rule_get_src_ip(ctx), - dplane_ctx_rule_get_dst_ip(ctx), - dplane_ctx_rule_get_fwmark(ctx)); + ret = netlink_batch_add_msg(bth, ctx, netlink_rule_msg_encoder, false); /** * Delete the old one. @@ -196,18 +206,10 @@ enum zebra_dplane_result kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx) * Don't care about this result right? */ if (op == DPLANE_OP_RULE_UPDATE) - netlink_rule_update_internal( - RTM_DELRULE, ctx, - dplane_ctx_rule_get_old_filter_bm(ctx), - dplane_ctx_rule_get_old_priority(ctx), - dplane_ctx_rule_get_old_table(ctx), - dplane_ctx_rule_get_old_src_ip(ctx), - dplane_ctx_rule_get_old_dst_ip(ctx), - dplane_ctx_rule_get_old_fwmark(ctx)); - - - return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS - : ZEBRA_DPLANE_REQUEST_FAILURE); + netlink_batch_add_msg(bth, ctx, netlink_oldrule_msg_encoder, + true); + + return ret; } /* @@ -247,7 +249,16 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } frh = NLMSG_DATA(h); + if (frh->family != AF_INET && frh->family != AF_INET6) { + if (frh->family == RTNL_FAMILY_IPMR + || frh->family == RTNL_FAMILY_IP6MR) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Received rule netlink that we are ignoring for family %u, rule change: %u", + frh->family, h->nlmsg_type); + return 0; + } flog_warn( EC_ZEBRA_NETLINK_INVALID_AF, "Invalid address family: %u received from kernel rule change: %u", |
