--- /dev/null
+#ifndef __LINUX_FIB_RULES_H
+#define __LINUX_FIB_RULES_H
+
+#include <linux/types.h>
+#include <linux/rtnetlink.h>
+
+/* rule is permanent, and cannot be deleted */
+#define FIB_RULE_PERMANENT 0x00000001
+#define FIB_RULE_INVERT 0x00000002
+#define FIB_RULE_UNRESOLVED 0x00000004
+#define FIB_RULE_IIF_DETACHED 0x00000008
+#define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED
+#define FIB_RULE_OIF_DETACHED 0x00000010
+
+/* try to find source address in routing lookups */
+#define FIB_RULE_FIND_SADDR 0x00010000
+
+struct fib_rule_hdr {
+ __u8 family;
+ __u8 dst_len;
+ __u8 src_len;
+ __u8 tos;
+
+ __u8 table;
+ __u8 res1; /* reserved */
+ __u8 res2; /* reserved */
+ __u8 action;
+
+ __u32 flags;
+};
+
+enum {
+ FRA_UNSPEC,
+ FRA_DST, /* destination address */
+ FRA_SRC, /* source address */
+ FRA_IIFNAME, /* interface name */
+#define FRA_IFNAME FRA_IIFNAME
+ FRA_GOTO, /* target to jump to (FR_ACT_GOTO) */
+ FRA_UNUSED2,
+ FRA_PRIORITY, /* priority/preference */
+ FRA_UNUSED3,
+ FRA_UNUSED4,
+ FRA_UNUSED5,
+ FRA_FWMARK, /* mark */
+ FRA_FLOW, /* flow/class id */
+ FRA_UNUSED6,
+ FRA_SUPPRESS_IFGROUP,
+ FRA_SUPPRESS_PREFIXLEN,
+ FRA_TABLE, /* Extended table id */
+ FRA_FWMASK, /* mask for netfilter mark */
+ FRA_OIFNAME,
+ FRA_PAD,
+ FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
+ __FRA_MAX
+};
+
+#define FRA_MAX (__FRA_MAX - 1)
+
+enum {
+ FR_ACT_UNSPEC,
+ FR_ACT_TO_TBL, /* Pass to fixed table */
+ FR_ACT_GOTO, /* Jump to another rule */
+ FR_ACT_NOP, /* No operation */
+ FR_ACT_RES3,
+ FR_ACT_RES4,
+ FR_ACT_BLACKHOLE, /* Drop without notification */
+ FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
+ FR_ACT_PROHIBIT, /* Drop with EACCES */
+ __FR_ACT_MAX,
+};
+
+#define FR_ACT_MAX (__FR_ACT_MAX - 1)
+
+#endif
include/linux/rtnetlink.h \
include/linux/socket.h \
include/linux/net_namespace.h \
+ include/linux/fib_rules.h \
# end
#include "zebra/kernel_netlink.h"
#include "zebra/rt_netlink.h"
#include "zebra/if_netlink.h"
+#include "zebra/rule_netlink.h"
#ifndef SO_RCVBUFFORCE
#define SO_RCVBUFFORCE (33)
{RTM_NEWNEIGH, "RTM_NEWNEIGH"},
{RTM_DELNEIGH, "RTM_DELNEIGH"},
{RTM_GETNEIGH, "RTM_GETNEIGH"},
+ {RTM_NEWRULE, "RTM_NEWRULE"},
+ {RTM_DELRULE, "RTM_DELRULE"},
+ {RTM_GETRULE, "RTM_GETRULE"},
{0}};
static const struct message rtproto_str[] = {
switch (h->nlmsg_type) {
case RTM_NEWROUTE:
return netlink_route_change(snl, h, ns_id, startup);
- break;
case RTM_DELROUTE:
return netlink_route_change(snl, h, ns_id, startup);
- break;
case RTM_NEWLINK:
return netlink_link_change(snl, h, ns_id, startup);
- break;
case RTM_DELLINK:
return netlink_link_change(snl, h, ns_id, startup);
- break;
case RTM_NEWADDR:
return netlink_interface_addr(snl, h, ns_id, startup);
- break;
case RTM_DELADDR:
return netlink_interface_addr(snl, h, ns_id, startup);
- break;
case RTM_NEWNEIGH:
return netlink_neigh_change(snl, h, ns_id);
- break;
case RTM_DELNEIGH:
return netlink_neigh_change(snl, h, ns_id);
- break;
+ case RTM_NEWRULE:
+ return netlink_rule_change(snl, h, ns_id, startup);
+ case RTM_DELRULE:
+ return netlink_rule_change(snl, h, ns_id, startup);
default:
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("Unknown netlink nlmsg_type %d vrf %u\n",
/* Initialize netlink sockets */
groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR
| RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_MROUTE
- | RTMGRP_NEIGH;
+ | RTMGRP_NEIGH
+ | RTNLGRP_IPV4_RULE | RTNLGRP_IPV6_RULE;
snprintf(zns->netlink.name, sizeof(zns->netlink.name),
"netlink-listen (NS %u)", zns->ns_id);
{
}
+void kernel_read_pbr_rules(struct zebra_ns *zns)
+{
+}
+
#endif /* SUNOS_5 */
#include "vty.h"
#include "zebra/rt.h"
+#include "zebra/zebra_pbr.h"
#include "zebra/rt_netlink.h"
+#include "zebra/rule_netlink.h"
void route_read(struct zebra_ns *zns)
{
netlink_neigh_read_for_vlan(zns, vlan_if);
}
+void kernel_read_pbr_rules(struct zebra_ns *zns)
+{
+ netlink_rules_read(zns);
+}
+
#endif /* GNU_LINUX */
#include "zebra/rt.h"
#include "zebra/kernel_socket.h"
+#include "zebra/zebra_pbr.h"
/* Kernel routing table read up by sysctl function. */
void route_read(struct zebra_ns *zns)
{
}
+void kernel_read_pbr_rules(struct zebra_ns *zns)
+{
+}
+
#endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */
--- /dev/null
+/*
+ * 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>
+
+#ifdef HAVE_NETLINK
+
+#include "if.h"
+#include "prefix.h"
+#include "vrf.h"
+
+#include <linux/fib_rules.h>
+#include "zebra/zserv.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/rt.h"
+#include "zebra/interface.h"
+#include "zebra/debug.h"
+#include "zebra/rtadv.h"
+#include "zebra/kernel_netlink.h"
+#include "zebra/rule_netlink.h"
+#include "zebra/zebra_pbr.h"
+
+/* definitions */
+
+/* static function declarations */
+
+/* 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.
+ */
+static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule,
+ struct interface *ifp, u_int32_t rule_pri)
+{
+ int family;
+ int bytelen;
+ 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 buf1[PREFIX_STRLEN];
+ char buf2[PREFIX_STRLEN];
+
+ memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE);
+ family = PREFIX_FAMILY(&rule->filter.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.frh.family = family;
+ req.frh.action = FR_ACT_TO_TBL;
+
+ if (cmd == RTM_NEWRULE)
+ req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+
+ /* rule's pref # */
+ addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule_pri);
+
+ /* interface on which applied */
+ addattr_l(&req.n, sizeof(req), FRA_IFNAME, ifp->name,
+ strlen(ifp->name)+1);
+
+ /* source IP, if specified */
+ if (IS_RULE_FILTERING_ON_SRC_IP(rule)) {
+ req.frh.src_len = rule->filter.src_ip.prefixlen;
+ addattr_l(&req.n, sizeof(req), FRA_SRC,
+ &rule->filter.src_ip.u.prefix, bytelen);
+ }
+ /* destination IP, if specified */
+ if (IS_RULE_FILTERING_ON_DST_IP(rule)) {
+ req.frh.dst_len = rule->filter.dst_ip.prefixlen;
+ addattr_l(&req.n, sizeof(req), FRA_DST,
+ &rule->filter.dst_ip.u.prefix, bytelen);
+ }
+
+ /* Route table to use to forward, if filter criteria matches. */
+ if (rule->action.table < 256)
+ req.frh.table = rule->action.table;
+ else {
+ req.frh.table = RT_TABLE_UNSPEC;
+ addattr32(&req.n, sizeof(req), FRA_TABLE,
+ rule->action.table);
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Tx %s family %s IF %s(%u) Pref %u Src %s "
+ "Dst %s Table %u",
+ nl_msg_type_to_str(cmd),
+ nl_family_to_str(family),
+ ifp->name, ifp->ifindex, rule_pri,
+ prefix2str(&rule->filter.src_ip, buf1, sizeof(buf1)),
+ prefix2str(&rule->filter.dst_ip, buf2, sizeof(buf2)),
+ rule->action.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);
+}
+
+
+/* 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.
+ */
+void kernel_add_pbr_rule(struct zebra_pbr_rule *rule,
+ struct interface *ifp, u_int32_t rule_pri)
+{
+ int ret = 0;
+
+ ret = netlink_rule_update(RTM_NEWRULE, rule, ifp, rule_pri);
+ kernel_pbr_rule_add_del_status(rule, ifp, rule_pri,
+ (!ret) ?
+ SOUTHBOUND_INSTALL_SUCCESS :
+ SOUTHBOUND_INSTALL_FAILURE);
+}
+
+/*
+ * Uninstall specified rule for a specific interface.
+ */
+void kernel_del_pbr_rule(struct zebra_pbr_rule *rule,
+ struct interface *ifp, u_int32_t rule_pri)
+{
+ int ret = 0;
+
+ ret = netlink_rule_update(RTM_DELRULE, rule, ifp, rule_pri);
+ kernel_pbr_rule_add_del_status(rule, ifp, rule_pri,
+ (!ret) ?
+ SOUTHBOUND_DELETE_SUCCESS :
+ SOUTHBOUND_DELETE_FAILURE);
+}
+
+/*
+ * Handle netlink notification informing a rule add or delete.
+ * Handling of an ADD is TBD.
+ * DELs are notified up, if other attributes indicate it may be a
+ * notification of interest. The expectation is that if this corresponds
+ * to a PBR rule added by FRR, it will be readded.
+ */
+int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
+ ns_id_t ns_id, int startup)
+{
+ struct zebra_ns *zns;
+ struct fib_rule_hdr *frh;
+ struct rtattr *tb[FRA_MAX + 1];
+ int len;
+ char *ifname;
+ struct interface *ifp;
+ u_int32_t rule_pri = 0;
+ struct zebra_pbr_rule rule;
+ char buf1[PREFIX_STRLEN];
+ char buf2[PREFIX_STRLEN];
+
+ /* Basic validation followed by extracting attributes. */
+ if (h->nlmsg_type != RTM_NEWRULE && h->nlmsg_type != RTM_DELRULE)
+ return 0;
+
+ /* TBD */
+ if (h->nlmsg_type == RTM_NEWRULE)
+ return 0;
+
+ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
+ if (len < 0)
+ return -1;
+
+ frh = NLMSG_DATA(h);
+ if (frh->family != AF_INET && frh->family != AF_INET6)
+ return 0;
+ if (frh->action != FR_ACT_TO_TBL)
+ return 0;
+
+ memset(tb, 0, sizeof(tb));
+ netlink_parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
+
+ /* TBD: We don't care about rules not specifying an IIF. */
+ if (tb[FRA_IFNAME] == NULL)
+ return 0;
+
+ /* If we don't know the interface, we don't care. */
+ ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);
+ zns = zebra_ns_lookup(ns_id);
+ ifp = if_lookup_by_name_per_ns(zns, ifname);
+ if (!ifp)
+ return 0;
+
+ memset(&rule, 0, sizeof(rule));
+ if (tb[FRA_PRIORITY])
+ rule_pri = *(u_int32_t *)RTA_DATA(tb[FRA_PRIORITY]);
+
+ if (tb[FRA_SRC]) {
+ if (frh->family == AF_INET)
+ memcpy(&rule.filter.src_ip.u.prefix4,
+ RTA_DATA(tb[FRA_SRC]), 4);
+ else
+ memcpy(&rule.filter.src_ip.u.prefix6,
+ RTA_DATA(tb[FRA_SRC]), 16);
+ rule.filter.src_ip.prefixlen = frh->src_len;
+ rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
+ }
+
+ if (tb[FRA_DST]) {
+ if (frh->family == AF_INET)
+ memcpy(&rule.filter.dst_ip.u.prefix4,
+ RTA_DATA(tb[FRA_DST]), 4);
+ else
+ memcpy(&rule.filter.dst_ip.u.prefix6,
+ RTA_DATA(tb[FRA_DST]), 16);
+ rule.filter.dst_ip.prefixlen = frh->dst_len;
+ rule.filter.filter_bm |= PBR_FILTER_DST_IP;
+ }
+
+ if (tb[FRA_TABLE])
+ rule.action.table = *(u_int32_t *)RTA_DATA(tb[FRA_TABLE]);
+ else
+ rule.action.table = frh->table;
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Rx %s family %s IF %s(%u) Pref %u Src %s "
+ "Dst %s Table %u",
+ nl_msg_type_to_str(h->nlmsg_type),
+ nl_family_to_str(frh->family),
+ ifp->name, ifp->ifindex, rule_pri,
+ prefix2str(&rule.filter.src_ip, buf1, sizeof(buf1)),
+ prefix2str(&rule.filter.dst_ip, buf2, sizeof(buf2)),
+ rule.action.table);
+
+ return kernel_pbr_rule_del(&rule, ifp, rule_pri);
+}
+
+/*
+ * Get to know existing PBR rules in the kernel - typically called at startup.
+ * TBD.
+ */
+int netlink_rules_read(struct zebra_ns *zns)
+{
+ return 0;
+}
+
+#endif /* HAVE_NETLINK */
--- /dev/null
+/*
+ * Zebra Policy Based Routing (PBR) interaction with the kernel using
+ * netlink - public definitions and function declarations.
+ * 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.
+ */
+
+#ifndef _ZEBRA_RULE_NETLINK_H
+#define _ZEBRA_RULE_NETLINK_H
+
+#ifdef HAVE_NETLINK
+
+/*
+ * Handle netlink notification informing a rule add or delete.
+ */
+extern int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
+ ns_id_t ns_id, int startup);
+
+/*
+ * Get to know existing PBR rules in the kernel - typically called at startup.
+ */
+extern int netlink_rules_read(struct zebra_ns *zns);
+
+#endif /* HAVE_NETLINK */
+
+#endif /* _ZEBRA_RULE_NETLINK_H */
--- /dev/null
+/*
+ * Zebra Policy Based Routing (PBR) interaction with the kernel using
+ * netlink.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * 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>
+
+#ifndef HAVE_NETLINK
+
+#include "if.h"
+#include "prefix.h"
+#include "vrf.h"
+
+#include "zebra/zserv.h"
+#include "zebra/zebra_ns.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/rt.h"
+#include "zebra/interface.h"
+#include "zebra/debug.h"
+#include "zebra/rtadv.h"
+#include "zebra/kernel_netlink.h"
+#include "zebra/rule_netlink.h"
+#include "zebra/zebra_pbr.h"
+
+void kernel_add_pbr_rule(struct zebra_pbr_rule *rule)
+{
+}
+void kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
+{
+}
+
+#endif
zebra/rtread_getmsg.c \
zebra/rtread_netlink.c \
zebra/rtread_sysctl.c \
+ zebra/rule_netlink.c \
+ zebra/rule_socket.c \
zebra/zebra_l2.c \
zebra/zebra_memory.c \
zebra/zebra_mpls.c \
zebra/zebra_mpls_vty.c \
zebra/zebra_mroute.c \
zebra/zebra_ns.c \
+ zebra/zebra_pbr.c \
zebra/zebra_ptm.c \
zebra/zebra_ptm_redistribute.c \
zebra/zebra_pw.c \
zebra/rt.h \
zebra/rt_netlink.h \
zebra/rtadv.h \
+ zebra/rule_netlink.h \
zebra/zebra_fpm_private.h \
zebra/zebra_l2.h \
zebra/zebra_memory.h \
zebra/zebra_mpls.h \
zebra/zebra_mroute.h \
zebra/zebra_ns.h \
+ zebra/zebra_pbr.h \
zebra/zebra_ptm.h \
zebra/zebra_ptm_redistribute.h \
zebra/zebra_pw.h \
#define __ZEBRA_NS_H__
#include <lib/ns.h>
+#include <lib/vrf.h>
#ifdef HAVE_NETLINK
/* Socket interface to kernel */
--- /dev/null
+/* Zebra Policy Based Routing (PBR) main handling.
+ * 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/rt.h"
+
+/* definitions */
+
+/* static function declarations */
+
+/* Private functions */
+
+/* Public functions */
+/*
+ * Handle success or failure of rule (un)install in the kernel.
+ */
+void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
+ struct interface *ifp,
+ u_int32_t rule_pri,
+ enum southbound_results res)
+{
+}
+
+/*
+ * Handle rule delete notification from kernel.
+ */
+int kernel_pbr_rule_del(struct zebra_pbr_rule *rule,
+ struct interface *ifp,
+ u_int32_t rule_pri)
+{
+ return 0;
+}
+
+
--- /dev/null
+/*
+ * Zebra Policy Based Routing (PBR) Data structures and definitions
+ * These are public definitions referenced by multiple files.
+ * 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.
+ */
+
+#ifndef _ZEBRA_PBR_H
+#define _ZEBRA_PBR_H
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "if.h"
+#include "rt.h"
+
+/*
+ * A PBR filter
+ *
+ * The filter or match criteria in a PBR rule.
+ * For simplicity, all supported filters are grouped into a structure rather
+ * than delineating further. A bitmask denotes which filters are actually
+ * specified.
+ */
+struct zebra_pbr_filter {
+ u_int32_t filter_bm;
+#define PBR_FILTER_SRC_IP (1 << 0)
+#define PBR_FILTER_DST_IP (1 << 1)
+#define PBR_FILTER_SRC_PORT (1 << 2)
+#define PBR_FILTER_DST_PORT (1 << 3)
+
+ /* Source and Destination IP address with masks. */
+ struct prefix src_ip;
+ struct prefix dst_ip;
+
+ /* Source and Destination higher-layer (TCP/UDP) port numbers. */
+ u_int16_t src_port;
+ u_int16_t dst_port;
+};
+
+#define IS_RULE_FILTERING_ON_SRC_IP(r) \
+ (r->filter.filter_bm & PBR_FILTER_SRC_IP)
+#define IS_RULE_FILTERING_ON_DST_IP(r) \
+ (r->filter.filter_bm & PBR_FILTER_DST_IP)
+#define IS_RULE_FILTERING_ON_SRC_PORT(r) \
+ (r->filter.filter_bm & PBR_FILTER_SRC_PORT)
+#define IS_RULE_FILTERING_ON_DST_PORT(r) \
+ (r->filter.filter_bm & PBR_FILTER_DST_PORT)
+
+/*
+ * A PBR action
+ *
+ * The action corresponding to a PBR rule.
+ * While the user specifies the action in a particular way, the forwarding
+ * plane implementation (Linux only) requires that to be encoded into a
+ * route table and the rule then point to that route table; in some cases,
+ * the user criteria may directly point to a table too.
+ */
+struct zebra_pbr_action {
+ u_int32_t table;
+};
+
+/*
+ * A PBR rule
+ *
+ * This is a combination of the filter criteria and corresponding action.
+ * Rules also have a user-defined sequence number which defines the relative
+ * order amongst rules.
+ */
+struct zebra_pbr_rule {
+ u_int32_t seq;
+ struct zebra_pbr_filter filter;
+ struct zebra_pbr_action action;
+};
+
+
+/*
+ * Install specified rule for a specific interface.
+ * It is possible that the user-defined sequence number and the one in the
+ * forwarding plane may not coincide, hence the API requires a separate
+ * rule priority - maps to preference/FRA_PRIORITY on Linux.
+ */
+extern void kernel_add_pbr_rule(struct zebra_pbr_rule *rule,
+ struct interface *ifp, u_int32_t rule_pri);
+
+/*
+ * Uninstall specified rule for a specific interface.
+ */
+extern void kernel_del_pbr_rule(struct zebra_pbr_rule *rule,
+ struct interface *ifp, u_int32_t rule_pri);
+
+/*
+ * Get to know existing PBR rules in the kernel - typically called at startup.
+ */
+extern void kernel_read_pbr_rules(struct zebra_ns *zns);
+
+/*
+ * Handle success or failure of rule (un)install in the kernel.
+ */
+extern void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule,
+ struct interface *ifp,
+ u_int32_t rule_pri,
+ enum southbound_results res);
+
+/*
+ * Handle rule delete notification from kernel.
+ */
+extern int kernel_pbr_rule_del(struct zebra_pbr_rule *rule,
+ struct interface *ifp,
+ u_int32_t rule_pri);
+
+#endif /* _ZEBRA_PBR_H */