]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rule_netlink.c
Merge pull request #2057 from donaldsharp/fix_1916
[mirror_frr.git] / zebra / rule_netlink.c
CommitLineData
942bf97b 1/*
2 * Zebra Policy Based Routing (PBR) interaction with the kernel using
3 * netlink.
4 * Copyright (C) 2018 Cumulus Networks, Inc.
5 *
6 * This file is part of FRR.
7 *
8 * FRR is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * FRR is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with FRR; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24#include <zebra.h>
25
26#ifdef HAVE_NETLINK
27
28#include "if.h"
29#include "prefix.h"
30#include "vrf.h"
31
32#include <linux/fib_rules.h>
33#include "zebra/zserv.h"
34#include "zebra/zebra_ns.h"
35#include "zebra/zebra_vrf.h"
36#include "zebra/rt.h"
37#include "zebra/interface.h"
38#include "zebra/debug.h"
39#include "zebra/rtadv.h"
40#include "zebra/kernel_netlink.h"
41#include "zebra/rule_netlink.h"
42#include "zebra/zebra_pbr.h"
43
44/* definitions */
45
46/* static function declarations */
47
48/* Private functions */
49
50/* Install or uninstall specified rule for a specific interface.
51 * Form netlink message and ship it. Currently, notify status after
52 * waiting for netlink status.
53 */
a0321978 54static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
942bf97b 55{
56 int family;
57 int bytelen;
58 struct {
59 struct nlmsghdr n;
60 struct fib_rule_hdr frh;
61 char buf[NL_PKT_BUF_SIZE];
62 } req;
63 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
64 struct sockaddr_nl snl;
65 char buf1[PREFIX_STRLEN];
66 char buf2[PREFIX_STRLEN];
67
fd71d73e 68 memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
5dd0722d 69 family = PREFIX_FAMILY(&rule->rule.filter.src_ip);
942bf97b 70 bytelen = (family == AF_INET ? 4 : 16);
71
72 req.n.nlmsg_type = cmd;
73 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
74 req.n.nlmsg_flags = NLM_F_REQUEST;
75 req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
76
77 req.frh.family = family;
78 req.frh.action = FR_ACT_TO_TBL;
79
942bf97b 80 /* rule's pref # */
5dd0722d 81 addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority);
942bf97b 82
83 /* interface on which applied */
a0321978
DS
84 if (rule->ifp)
85 addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifp->name,
86 strlen(rule->ifp->name) + 1);
942bf97b 87
88 /* source IP, if specified */
89 if (IS_RULE_FILTERING_ON_SRC_IP(rule)) {
5dd0722d 90 req.frh.src_len = rule->rule.filter.src_ip.prefixlen;
942bf97b 91 addattr_l(&req.n, sizeof(req), FRA_SRC,
5dd0722d 92 &rule->rule.filter.src_ip.u.prefix, bytelen);
942bf97b 93 }
94 /* destination IP, if specified */
95 if (IS_RULE_FILTERING_ON_DST_IP(rule)) {
5dd0722d 96 req.frh.dst_len = rule->rule.filter.dst_ip.prefixlen;
942bf97b 97 addattr_l(&req.n, sizeof(req), FRA_DST,
5dd0722d 98 &rule->rule.filter.dst_ip.u.prefix, bytelen);
942bf97b 99 }
100
101 /* Route table to use to forward, if filter criteria matches. */
5dd0722d
PG
102 if (rule->rule.action.table < 256)
103 req.frh.table = rule->rule.action.table;
942bf97b 104 else {
105 req.frh.table = RT_TABLE_UNSPEC;
106 addattr32(&req.n, sizeof(req), FRA_TABLE,
5dd0722d 107 rule->rule.action.table);
942bf97b 108 }
109
110 if (IS_ZEBRA_DEBUG_KERNEL)
fd71d73e
DS
111 zlog_debug(
112 "Tx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
113 nl_msg_type_to_str(cmd), nl_family_to_str(family),
a0321978 114 rule->ifp ? rule->ifp->name : "Unknown",
5dd0722d
PG
115 rule->ifp ? rule->ifp->ifindex : 0, rule->rule.priority,
116 prefix2str(&rule->rule.filter.src_ip, buf1,
117 sizeof(buf1)),
118 prefix2str(&rule->rule.filter.dst_ip, buf2,
119 sizeof(buf2)),
120 rule->rule.action.table);
942bf97b 121
122 /* Ship off the message.
123 * Note: Currently, netlink_talk() is a blocking call which returns
124 * back the status.
125 */
126 memset(&snl, 0, sizeof(snl));
127 snl.nl_family = AF_NETLINK;
128 return netlink_talk(netlink_talk_filter, &req.n,
129 &zns->netlink_cmd, zns, 0);
130}
131
132
133/* Public functions */
134/*
135 * Install specified rule for a specific interface. The preference is what
136 * goes in the rule to denote relative ordering; it may or may not be the
137 * same as the rule's user-defined sequence number.
138 */
a0321978 139void kernel_add_pbr_rule(struct zebra_pbr_rule *rule)
942bf97b 140{
141 int ret = 0;
142
a0321978
DS
143 ret = netlink_rule_update(RTM_NEWRULE, rule);
144 kernel_pbr_rule_add_del_status(rule,
fd71d73e
DS
145 (!ret) ? SOUTHBOUND_INSTALL_SUCCESS
146 : SOUTHBOUND_INSTALL_FAILURE);
942bf97b 147}
148
149/*
150 * Uninstall specified rule for a specific interface.
151 */
a0321978 152void kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
942bf97b 153{
154 int ret = 0;
155
a0321978
DS
156 ret = netlink_rule_update(RTM_DELRULE, rule);
157 kernel_pbr_rule_add_del_status(rule,
fd71d73e
DS
158 (!ret) ? SOUTHBOUND_DELETE_SUCCESS
159 : SOUTHBOUND_DELETE_FAILURE);
942bf97b 160}
161
162/*
163 * Handle netlink notification informing a rule add or delete.
164 * Handling of an ADD is TBD.
165 * DELs are notified up, if other attributes indicate it may be a
166 * notification of interest. The expectation is that if this corresponds
167 * to a PBR rule added by FRR, it will be readded.
168 */
169int netlink_rule_change(struct sockaddr_nl *snl, struct nlmsghdr *h,
170 ns_id_t ns_id, int startup)
171{
172 struct zebra_ns *zns;
173 struct fib_rule_hdr *frh;
174 struct rtattr *tb[FRA_MAX + 1];
175 int len;
176 char *ifname;
942bf97b 177 struct zebra_pbr_rule rule;
178 char buf1[PREFIX_STRLEN];
179 char buf2[PREFIX_STRLEN];
180
181 /* Basic validation followed by extracting attributes. */
182 if (h->nlmsg_type != RTM_NEWRULE && h->nlmsg_type != RTM_DELRULE)
183 return 0;
184
185 /* TBD */
186 if (h->nlmsg_type == RTM_NEWRULE)
187 return 0;
188
189 len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
190 if (len < 0)
191 return -1;
192
193 frh = NLMSG_DATA(h);
194 if (frh->family != AF_INET && frh->family != AF_INET6)
195 return 0;
196 if (frh->action != FR_ACT_TO_TBL)
197 return 0;
198
199 memset(tb, 0, sizeof(tb));
200 netlink_parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
201
202 /* TBD: We don't care about rules not specifying an IIF. */
203 if (tb[FRA_IFNAME] == NULL)
204 return 0;
205
206 /* If we don't know the interface, we don't care. */
207 ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);
208 zns = zebra_ns_lookup(ns_id);
a0321978
DS
209 rule.ifp = if_lookup_by_name_per_ns(zns, ifname);
210 if (!rule.ifp)
942bf97b 211 return 0;
212
213 memset(&rule, 0, sizeof(rule));
214 if (tb[FRA_PRIORITY])
5dd0722d 215 rule.rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]);
942bf97b 216
217 if (tb[FRA_SRC]) {
218 if (frh->family == AF_INET)
5dd0722d 219 memcpy(&rule.rule.filter.src_ip.u.prefix4,
942bf97b 220 RTA_DATA(tb[FRA_SRC]), 4);
221 else
5dd0722d 222 memcpy(&rule.rule.filter.src_ip.u.prefix6,
942bf97b 223 RTA_DATA(tb[FRA_SRC]), 16);
5dd0722d
PG
224 rule.rule.filter.src_ip.prefixlen = frh->src_len;
225 rule.rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
942bf97b 226 }
227
228 if (tb[FRA_DST]) {
229 if (frh->family == AF_INET)
5dd0722d 230 memcpy(&rule.rule.filter.dst_ip.u.prefix4,
942bf97b 231 RTA_DATA(tb[FRA_DST]), 4);
232 else
5dd0722d 233 memcpy(&rule.rule.filter.dst_ip.u.prefix6,
942bf97b 234 RTA_DATA(tb[FRA_DST]), 16);
5dd0722d
PG
235 rule.rule.filter.dst_ip.prefixlen = frh->dst_len;
236 rule.rule.filter.filter_bm |= PBR_FILTER_DST_IP;
942bf97b 237 }
238
239 if (tb[FRA_TABLE])
5dd0722d 240 rule.rule.action.table = *(uint32_t *)RTA_DATA(tb[FRA_TABLE]);
942bf97b 241 else
5dd0722d 242 rule.rule.action.table = frh->table;
942bf97b 243
244 if (IS_ZEBRA_DEBUG_KERNEL)
fd71d73e
DS
245 zlog_debug(
246 "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
247 nl_msg_type_to_str(h->nlmsg_type),
a0321978 248 nl_family_to_str(frh->family), rule.ifp->name,
5dd0722d
PG
249 rule.ifp->ifindex, rule.rule.priority,
250 prefix2str(&rule.rule.filter.src_ip, buf1,
251 sizeof(buf1)),
252 prefix2str(&rule.rule.filter.dst_ip, buf2,
253 sizeof(buf2)),
254 rule.rule.action.table);
fd71d73e 255
a0321978 256 return kernel_pbr_rule_del(&rule);
942bf97b 257}
258
259/*
260 * Get to know existing PBR rules in the kernel - typically called at startup.
261 * TBD.
262 */
263int netlink_rules_read(struct zebra_ns *zns)
264{
265 return 0;
266}
267
268#endif /* HAVE_NETLINK */