]> git.proxmox.com Git - mirror_frr.git/commitdiff
*: PBR - netlink interaction and basic definitions
authorvivek <vivek@cumulusnetworks.com>
Sun, 4 Feb 2018 12:33:33 +0000 (12:33 +0000)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 9 Mar 2018 16:07:41 +0000 (11:07 -0500)
Implement netlink interactions for Policy Based Routing. This includes
APIs to install and uninstall rules and handle notifications from the
kernel related to rule addition or deletion. Various definitions are
added to facilitate this.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
13 files changed:
include/linux/fib_rules.h [new file with mode: 0644]
include/subdir.am
zebra/kernel_netlink.c
zebra/rtread_getmsg.c
zebra/rtread_netlink.c
zebra/rtread_sysctl.c
zebra/rule_netlink.c [new file with mode: 0644]
zebra/rule_netlink.h [new file with mode: 0644]
zebra/rule_socket.c [new file with mode: 0644]
zebra/subdir.am
zebra/zebra_ns.h
zebra/zebra_pbr.c [new file with mode: 0644]
zebra/zebra_pbr.h [new file with mode: 0644]

diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
new file mode 100644 (file)
index 0000000..bc66880
--- /dev/null
@@ -0,0 +1,74 @@
+#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
index 7a12b2ffae990410842e78cdeee675b5f0b17c78..db5ed06c61e85880c8a6010c6513aeb5e326cc94 100644 (file)
@@ -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
index 0b3b6eed45761b5db16ce36e597f6187ba5d0978..52b26920901bada0982a9d5ce77451c07117f688 100644 (file)
@@ -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);
index 95bc8db1c92fff2fb27f1614cc4cb990f9338753..38321bc4161a87eac6cdf94f37f5aae412441346 100644 (file)
@@ -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 */
index ec29d1820ece9d5680cbc41af3be2f6af8aff88d..e9920460785cdf85931b4d0316d3c51048e727a4 100644 (file)
@@ -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 */
index 4f5a80612ee6977c4c3b4c0a320ffe7f99f3ca33..fba67e3d0c4991a3e4d9fcabdf13ee1164114e4b 100644 (file)
@@ -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 (file)
index 0000000..4b8791e
--- /dev/null
@@ -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 <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 */
diff --git a/zebra/rule_netlink.h b/zebra/rule_netlink.h
new file mode 100644 (file)
index 0000000..034068b
--- /dev/null
@@ -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 (file)
index 0000000..46c53f9
--- /dev/null
@@ -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 <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
index bb7439c0f617625168abc430d8006ef32d23d668..ef157b7539e84787df7f7fe4bd378ff7d4940d4e 100644 (file)
@@ -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 \
index 3a998a49ff54b5a26e1d2670c6a8eb524944cde2..1d7b6f725e07a5b970434bcf95fbb6735337de35 100644 (file)
@@ -23,6 +23,7 @@
 #define __ZEBRA_NS_H__
 
 #include <lib/ns.h>
+#include <lib/vrf.h>
 
 #ifdef HAVE_NETLINK
 /* Socket interface to kernel */
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
new file mode 100644 (file)
index 0000000..6e521be
--- /dev/null
@@ -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 <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;
+}
+
+
diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h
new file mode 100644 (file)
index 0000000..2e80aeb
--- /dev/null
@@ -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 <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 */