diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h new file mode 100644 index 0000000000..bc6688012c --- /dev/null +++ b/include/linux/fib_rules.h @@ -0,0 +1,74 @@ +#ifndef __LINUX_FIB_RULES_H +#define __LINUX_FIB_RULES_H + +#include +#include + +/* 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 diff --git a/include/subdir.am b/include/subdir.am index 7a12b2ffae..db5ed06c61 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -7,4 +7,5 @@ noinst_HEADERS += \ include/linux/rtnetlink.h \ include/linux/socket.h \ include/linux/net_namespace.h \ + include/linux/fib_rules.h \ # end diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 0b3b6eed45..52b2692090 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -45,6 +45,7 @@ #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) @@ -85,6 +86,9 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {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[] = { @@ -240,28 +244,24 @@ static int netlink_information_fetch(struct sockaddr_nl *snl, 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", @@ -788,7 +788,8 @@ void kernel_init(struct zebra_ns *zns) /* 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); diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c index 95bc8db1c9..38321bc416 100644 --- a/zebra/rtread_getmsg.c +++ b/zebra/rtread_getmsg.c @@ -263,4 +263,8 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } +void kernel_read_pbr_rules(struct zebra_ns *zns) +{ +} + #endif /* SUNOS_5 */ diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c index ec29d1820e..e992046078 100644 --- a/zebra/rtread_netlink.c +++ b/zebra/rtread_netlink.c @@ -25,7 +25,9 @@ #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) { @@ -53,4 +55,9 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) netlink_neigh_read_for_vlan(zns, vlan_if); } +void kernel_read_pbr_rules(struct zebra_ns *zns) +{ + netlink_rules_read(zns); +} + #endif /* GNU_LINUX */ diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index 4f5a80612e..fba67e3d0c 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -30,6 +30,7 @@ #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) @@ -92,4 +93,8 @@ void neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { } +void kernel_read_pbr_rules(struct zebra_ns *zns) +{ +} + #endif /* !defined(GNU_LINUX) && !defined(SUNOS_5) */ diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c new file mode 100644 index 0000000000..4b8791ee2f --- /dev/null +++ b/zebra/rule_netlink.c @@ -0,0 +1,273 @@ +/* + * 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 + +#ifdef HAVE_NETLINK + +#include "if.h" +#include "prefix.h" +#include "vrf.h" + +#include +#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 */ diff --git a/zebra/rule_netlink.h b/zebra/rule_netlink.h new file mode 100644 index 0000000000..034068b899 --- /dev/null +++ b/zebra/rule_netlink.h @@ -0,0 +1,42 @@ +/* + * 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 */ diff --git a/zebra/rule_socket.c b/zebra/rule_socket.c new file mode 100644 index 0000000000..46c53f9e02 --- /dev/null +++ b/zebra/rule_socket.c @@ -0,0 +1,51 @@ +/* + * 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 + +#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 diff --git a/zebra/subdir.am b/zebra/subdir.am index bb7439c0f6..ef157b7539 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -45,6 +45,8 @@ zebra_zebra_SOURCES = \ 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 \ @@ -54,6 +56,7 @@ zebra_zebra_SOURCES = \ 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 \ @@ -90,12 +93,14 @@ noinst_HEADERS += \ 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 \ diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 3a998a49ff..1d7b6f725e 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -23,6 +23,7 @@ #define __ZEBRA_NS_H__ #include +#include #ifdef HAVE_NETLINK /* Socket interface to kernel */ diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c new file mode 100644 index 0000000000..6e521be39e --- /dev/null +++ b/zebra/zebra_pbr.c @@ -0,0 +1,54 @@ +/* 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 + +#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; +} + + diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h new file mode 100644 index 0000000000..2e80aeb8a3 --- /dev/null +++ b/zebra/zebra_pbr.h @@ -0,0 +1,128 @@ +/* + * 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 + +#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 */