+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Zebra Policy Based Routing (PBR) interaction with the kernel using
* netlink.
* Copyright (C) 2018 Cumulus Networks, Inc.
- *
- * This file is part of FRR.
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
*/
#include <zebra.h>
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_dplane.h"
+#include "zebra/zebra_trace.h"
/* definitions */
* 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,
- uint8_t dsfield, 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,
+ uint8_t ip_protocol, void *buf, size_t buflen)
{
uint8_t protocol = RTPROT_ZEBRA;
int family;
if (filter_bm & PBR_FILTER_DSFIELD)
req->frh.tos = dsfield;
+ /* protocol to match on */
+ if (filter_bm & PBR_FILTER_IP_PROTOCOL)
+ nl_attr_put8(&req->n, buflen, FRA_IP_PROTO, ip_protocol);
+
/* Route table to use to forward, if filter criteria matches. */
if (table < 256)
req->frh.table = table;
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);
+ dplane_ctx_rule_get_dsfield(ctx),
+ dplane_ctx_rule_get_ipproto(ctx), buf, buflen);
}
static ssize_t netlink_oldrule_msg_encoder(struct zebra_dplane_ctx *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);
+ dplane_ctx_rule_get_old_dsfield(ctx),
+ dplane_ctx_rule_get_old_ipproto(ctx), buf, buflen);
}
/* Public functions */
char *ifname;
struct zebra_pbr_rule rule = {};
uint8_t proto = 0;
+ uint8_t ip_proto = 0;
+
+ frrtrace(3, frr_zebra, netlink_rule_change, h, ns_id, startup);
/* Basic validation followed by extracting attributes. */
if (h->nlmsg_type != RTM_NEWRULE && h->nlmsg_type != RTM_DELRULE)
if (tb[FRA_PROTOCOL])
proto = *(uint8_t *)RTA_DATA(tb[FRA_PROTOCOL]);
+ if (tb[FRA_IP_PROTO])
+ ip_proto = *(uint8_t *)RTA_DATA(tb[FRA_IP_PROTO]);
+
ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);
strlcpy(rule.ifname, ifname, sizeof(rule.ifname));
ret = dplane_pbr_rule_delete(&rule);
zlog_debug(
- "%s: %s leftover rule: family %s IF %s Pref %u Src %pFX Dst %pFX Table %u",
+ "%s: %s leftover rule: family %s IF %s Pref %u Src %pFX Dst %pFX Table %u ip-proto: %u",
__func__,
((ret == ZEBRA_DPLANE_REQUEST_FAILURE)
? "Failed to remove"
nl_family_to_str(frh->family), rule.ifname,
rule.rule.priority, &rule.rule.filter.src_ip,
&rule.rule.filter.dst_ip,
- rule.rule.action.table);
+ rule.rule.action.table, ip_proto);
}
/* TBD */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "Rx %s family %s IF %s Pref %u Src %pFX Dst %pFX Table %u",
+ "Rx %s family %s IF %s Pref %u Src %pFX Dst %pFX Table %u ip-proto: %u",
nl_msg_type_to_str(h->nlmsg_type),
nl_family_to_str(frh->family), rule.ifname,
rule.rule.priority, &rule.rule.filter.src_ip,
- &rule.rule.filter.dst_ip, rule.rule.action.table);
+ &rule.rule.filter.dst_ip, rule.rule.action.table,
+ ip_proto);
return kernel_pbr_rule_del(&rule);
}
return ret;
ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd,
- &dp_info, 0, 1);
+ &dp_info, 0, true);
if (ret < 0)
return ret;
return ret;
ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd,
- &dp_info, 0, 1);
+ &dp_info, 0, true);
return ret;
}