summaryrefslogtreecommitdiff
path: root/zebra/rule_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/rule_netlink.c')
-rw-r--r--zebra/rule_netlink.c107
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",