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.c196
1 files changed, 99 insertions, 97 deletions
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index a5a605f27e..9da008bb61 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -41,6 +41,7 @@
#include "zebra/rule_netlink.h"
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_errors.h"
+#include "zebra/zebra_dplane.h"
/* definitions */
@@ -48,11 +49,19 @@
/* Private functions */
-/* Install or uninstall specified rule for a specific interface.
- * Form netlink message and ship it. Currently, notify status after
- * waiting for netlink status.
+
+/*
+ * netlink_rule_msg_encode
+ *
+ * Encodes netlink RTM_ADDRULE/RTM_DELRULE message to buffer buf of size buflen.
+ *
+ * Returns -1 on failure or the number of bytes
+ * written to buf.
*/
-static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
+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)
{
uint8_t protocol = RTPROT_ZEBRA;
int family;
@@ -60,142 +69,133 @@ static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
struct {
struct nlmsghdr n;
struct fib_rule_hdr frh;
- char buf[NL_PKT_BUF_SIZE];
- } req;
- struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
- struct sockaddr_nl snl;
+ char buf[];
+ } *req = buf;
+
+ const char *ifname = dplane_ctx_get_ifname(ctx);
char buf1[PREFIX_STRLEN];
char buf2[PREFIX_STRLEN];
- memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
- family = PREFIX_FAMILY(&rule->rule.filter.src_ip);
+ memset(req, 0, sizeof(*req));
+ family = PREFIX_FAMILY(src_ip);
bytelen = (family == AF_INET ? 4 : 16);
- req.n.nlmsg_type = cmd;
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
- req.n.nlmsg_flags = NLM_F_REQUEST;
- req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
+ req->n.nlmsg_type = cmd;
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req->n.nlmsg_flags = NLM_F_REQUEST;
- req.frh.family = family;
- req.frh.action = FR_ACT_TO_TBL;
+ req->frh.family = family;
+ req->frh.action = FR_ACT_TO_TBL;
- addattr_l(&req.n, sizeof(req),
- FRA_PROTOCOL, &protocol, sizeof(protocol));
+ addattr_l(&req->n, buflen, FRA_PROTOCOL, &protocol, sizeof(protocol));
/* rule's pref # */
- addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority);
+ addattr32(&req->n, buflen, FRA_PRIORITY, priority);
/* interface on which applied */
- addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifname,
- strlen(rule->ifname) + 1);
+ addattr_l(&req->n, buflen, FRA_IFNAME, ifname, strlen(ifname) + 1);
/* source IP, if specified */
- if (IS_RULE_FILTERING_ON_SRC_IP(rule)) {
- req.frh.src_len = rule->rule.filter.src_ip.prefixlen;
- addattr_l(&req.n, sizeof(req), FRA_SRC,
- &rule->rule.filter.src_ip.u.prefix, bytelen);
+ if (filter_bm & PBR_FILTER_SRC_IP) {
+ req->frh.src_len = src_ip->prefixlen;
+ addattr_l(&req->n, buflen, FRA_SRC, &src_ip->u.prefix, bytelen);
}
+
/* destination IP, if specified */
- if (IS_RULE_FILTERING_ON_DST_IP(rule)) {
- req.frh.dst_len = rule->rule.filter.dst_ip.prefixlen;
- addattr_l(&req.n, sizeof(req), FRA_DST,
- &rule->rule.filter.dst_ip.u.prefix, bytelen);
+ if (filter_bm & PBR_FILTER_DST_IP) {
+ req->frh.dst_len = dst_ip->prefixlen;
+ addattr_l(&req->n, buflen, FRA_DST, &dst_ip->u.prefix, bytelen);
}
/* fwmark, if specified */
- if (IS_RULE_FILTERING_ON_FWMARK(rule)) {
- addattr32(&req.n, sizeof(req), FRA_FWMARK,
- rule->rule.filter.fwmark);
- }
+ if (filter_bm & PBR_FILTER_FWMARK)
+ addattr32(&req->n, buflen, FRA_FWMARK, fwmark);
/* Route table to use to forward, if filter criteria matches. */
- if (rule->rule.action.table < 256)
- req.frh.table = rule->rule.action.table;
+ if (table < 256)
+ req->frh.table = table;
else {
- req.frh.table = RT_TABLE_UNSPEC;
- addattr32(&req.n, sizeof(req), FRA_TABLE,
- rule->rule.action.table);
+ req->frh.table = RT_TABLE_UNSPEC;
+ addattr32(&req->n, buflen, FRA_TABLE, table);
}
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
"Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u",
nl_msg_type_to_str(cmd), nl_family_to_str(family),
- rule->ifname, rule->rule.ifindex, rule->rule.priority,
- rule->rule.filter.fwmark,
- prefix2str(&rule->rule.filter.src_ip, buf1,
- sizeof(buf1)),
- prefix2str(&rule->rule.filter.dst_ip, buf2,
- sizeof(buf2)),
- rule->rule.action.table);
+ ifname, dplane_ctx_get_ifindex(ctx), priority, fwmark,
+ prefix2str(src_ip, buf1, sizeof(buf1)),
+ prefix2str(dst_ip, buf2, sizeof(buf2)), table);
- /* Ship off the message.
- * Note: Currently, netlink_talk() is a blocking call which returns
- * back the status.
- */
- memset(&snl, 0, sizeof(snl));
- snl.nl_family = AF_NETLINK;
- return netlink_talk(netlink_talk_filter, &req.n,
- &zns->netlink_cmd, zns, 0);
+ return NLMSG_ALIGN(req->n.nlmsg_len);
}
-
-/* Public functions */
-/*
- * Install specified rule for a specific interface. The preference is what
- * goes in the rule to denote relative ordering; it may or may not be the
- * same as the rule's user-defined sequence number.
+/* Install or uninstall specified rule for a specific interface.
+ * Form netlink message and ship it.
*/
-enum zebra_dplane_result kernel_add_pbr_rule(struct zebra_pbr_rule *rule)
+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)
{
- int ret = 0;
+ char buf[NL_PKT_BUF_SIZE];
- ret = netlink_rule_update(RTM_NEWRULE, rule);
- kernel_pbr_rule_add_del_status(rule,
- (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
- : ZEBRA_DPLANE_INSTALL_FAILURE);
-
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
+ 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);
}
+/* Public functions */
/*
- * Uninstall specified rule for a specific interface.
+ * Add, update or delete a rule from the
+ * kernel, using info from a dataplane context.
*/
-enum zebra_dplane_result kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
+enum zebra_dplane_result kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx)
{
- int ret = 0;
-
- ret = netlink_rule_update(RTM_DELRULE, rule);
- kernel_pbr_rule_add_del_status(rule,
- (!ret) ? ZEBRA_DPLANE_DELETE_SUCCESS
- : ZEBRA_DPLANE_DELETE_FAILURE);
-
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
-}
+ enum dplane_op_e op;
+ int cmd;
+ int ret;
-/*
- * Update specified rule for a specific interface.
- */
-enum zebra_dplane_result kernel_update_pbr_rule(struct zebra_pbr_rule *old_rule,
- struct zebra_pbr_rule *new_rule)
-{
- int ret = 0;
+ 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 {
+ flog_err(
+ EC_ZEBRA_PBR_RULE_UPDATE,
+ "Context received for kernel rule update with incorrect OP code (%u)",
+ op);
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
+ }
- /* Add the new, updated one */
- ret = netlink_rule_update(RTM_NEWRULE, new_rule);
+ 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));
/**
* Delete the old one.
*
* Don't care about this result right?
*/
- netlink_rule_update(RTM_DELRULE, old_rule);
-
- kernel_pbr_rule_add_del_status(new_rule,
- (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
- : ZEBRA_DPLANE_INSTALL_FAILURE);
-
- return ZEBRA_DPLANE_REQUEST_SUCCESS;
+ 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);
}
/*
@@ -296,14 +296,16 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
* It should have been flushed on a previous shutdown.
*/
if (startup && proto == RTPROT_ZEBRA) {
- int ret;
+ enum zebra_dplane_result ret;
- ret = netlink_rule_update(RTM_DELRULE, &rule);
+ ret = dplane_pbr_rule_delete(&rule);
zlog_debug(
"%s: %s leftover rule: family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
__func__,
- ((ret == 0) ? "Removed" : "Failed to remove"),
+ ((ret == ZEBRA_DPLANE_REQUEST_FAILURE)
+ ? "Failed to remove"
+ : "Removed"),
nl_family_to_str(frh->family), rule.ifname,
rule.rule.ifindex, rule.rule.priority,
prefix2str(&rule.rule.filter.src_ip, buf1,