]> git.proxmox.com Git - mirror_frr.git/blob - zebra/rule_netlink.c
Merge pull request #3692 from nitinsoniism/valgrind_errors_fix
[mirror_frr.git] / zebra / rule_netlink.c
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 #include "zebra/zebra_errors.h"
44
45 /* definitions */
46
47 /* static function declarations */
48
49 /* Private functions */
50
51 /* Install or uninstall specified rule for a specific interface.
52 * Form netlink message and ship it. Currently, notify status after
53 * waiting for netlink status.
54 */
55 static int netlink_rule_update(int cmd, struct zebra_pbr_rule *rule)
56 {
57 int family;
58 int bytelen;
59 struct {
60 struct nlmsghdr n;
61 struct fib_rule_hdr frh;
62 char buf[NL_PKT_BUF_SIZE];
63 } req;
64 struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
65 struct sockaddr_nl snl;
66 char buf1[PREFIX_STRLEN];
67 char buf2[PREFIX_STRLEN];
68
69 memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
70 family = PREFIX_FAMILY(&rule->rule.filter.src_ip);
71 bytelen = (family == AF_INET ? 4 : 16);
72
73 req.n.nlmsg_type = cmd;
74 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
75 req.n.nlmsg_flags = NLM_F_REQUEST;
76 req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
77
78 req.frh.family = family;
79 req.frh.action = FR_ACT_TO_TBL;
80
81 /* rule's pref # */
82 addattr32(&req.n, sizeof(req), FRA_PRIORITY, rule->rule.priority);
83
84 /* interface on which applied */
85 if (rule->ifp)
86 addattr_l(&req.n, sizeof(req), FRA_IFNAME, rule->ifp->name,
87 strlen(rule->ifp->name) + 1);
88
89 /* source IP, if specified */
90 if (IS_RULE_FILTERING_ON_SRC_IP(rule)) {
91 req.frh.src_len = rule->rule.filter.src_ip.prefixlen;
92 addattr_l(&req.n, sizeof(req), FRA_SRC,
93 &rule->rule.filter.src_ip.u.prefix, bytelen);
94 }
95 /* destination IP, if specified */
96 if (IS_RULE_FILTERING_ON_DST_IP(rule)) {
97 req.frh.dst_len = rule->rule.filter.dst_ip.prefixlen;
98 addattr_l(&req.n, sizeof(req), FRA_DST,
99 &rule->rule.filter.dst_ip.u.prefix, bytelen);
100 }
101
102 /* fwmark, if specified */
103 if (IS_RULE_FILTERING_ON_FWMARK(rule)) {
104 addattr32(&req.n, sizeof(req), FRA_FWMARK,
105 rule->rule.filter.fwmark);
106 }
107
108 /* Route table to use to forward, if filter criteria matches. */
109 if (rule->rule.action.table < 256)
110 req.frh.table = rule->rule.action.table;
111 else {
112 req.frh.table = RT_TABLE_UNSPEC;
113 addattr32(&req.n, sizeof(req), FRA_TABLE,
114 rule->rule.action.table);
115 }
116
117 if (IS_ZEBRA_DEBUG_KERNEL)
118 zlog_debug(
119 "Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u",
120 nl_msg_type_to_str(cmd), nl_family_to_str(family),
121 rule->ifp ? rule->ifp->name : "Unknown",
122 rule->ifp ? rule->ifp->ifindex : 0, rule->rule.priority,
123 rule->rule.filter.fwmark,
124 prefix2str(&rule->rule.filter.src_ip, buf1,
125 sizeof(buf1)),
126 prefix2str(&rule->rule.filter.dst_ip, buf2,
127 sizeof(buf2)),
128 rule->rule.action.table);
129
130 /* Ship off the message.
131 * Note: Currently, netlink_talk() is a blocking call which returns
132 * back the status.
133 */
134 memset(&snl, 0, sizeof(snl));
135 snl.nl_family = AF_NETLINK;
136 return netlink_talk(netlink_talk_filter, &req.n,
137 &zns->netlink_cmd, zns, 0);
138 }
139
140
141 /* Public functions */
142 /*
143 * Install specified rule for a specific interface. The preference is what
144 * goes in the rule to denote relative ordering; it may or may not be the
145 * same as the rule's user-defined sequence number.
146 */
147 enum zebra_dplane_result kernel_add_pbr_rule(struct zebra_pbr_rule *rule)
148 {
149 int ret = 0;
150
151 ret = netlink_rule_update(RTM_NEWRULE, rule);
152 kernel_pbr_rule_add_del_status(rule,
153 (!ret) ? ZEBRA_DPLANE_INSTALL_SUCCESS
154 : ZEBRA_DPLANE_INSTALL_FAILURE);
155
156 return ZEBRA_DPLANE_REQUEST_SUCCESS;
157 }
158
159 /*
160 * Uninstall specified rule for a specific interface.
161 */
162 enum zebra_dplane_result kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
163 {
164 int ret = 0;
165
166 ret = netlink_rule_update(RTM_DELRULE, rule);
167 kernel_pbr_rule_add_del_status(rule,
168 (!ret) ? ZEBRA_DPLANE_DELETE_SUCCESS
169 : ZEBRA_DPLANE_DELETE_FAILURE);
170
171 return ZEBRA_DPLANE_REQUEST_SUCCESS;
172 }
173
174 /*
175 * Handle netlink notification informing a rule add or delete.
176 * Handling of an ADD is TBD.
177 * DELs are notified up, if other attributes indicate it may be a
178 * notification of interest. The expectation is that if this corresponds
179 * to a PBR rule added by FRR, it will be readded.
180 */
181 int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
182 {
183 struct zebra_ns *zns;
184 struct fib_rule_hdr *frh;
185 struct rtattr *tb[FRA_MAX + 1];
186 int len;
187 char *ifname;
188 struct zebra_pbr_rule rule;
189 char buf1[PREFIX_STRLEN];
190 char buf2[PREFIX_STRLEN];
191
192 /* Basic validation followed by extracting attributes. */
193 if (h->nlmsg_type != RTM_NEWRULE && h->nlmsg_type != RTM_DELRULE)
194 return 0;
195
196 /* TBD */
197 if (h->nlmsg_type == RTM_NEWRULE)
198 return 0;
199
200 len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr));
201 if (len < 0) {
202 zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
203 __PRETTY_FUNCTION__, h->nlmsg_len,
204 (size_t)NLMSG_LENGTH(sizeof(struct fib_rule_hdr)));
205 return -1;
206 }
207
208 frh = NLMSG_DATA(h);
209 if (frh->family != AF_INET && frh->family != AF_INET6) {
210 flog_warn(
211 EC_ZEBRA_NETLINK_INVALID_AF,
212 "Invalid address family: %u received from kernel rule change: %u",
213 frh->family, h->nlmsg_type);
214 return 0;
215 }
216 if (frh->action != FR_ACT_TO_TBL)
217 return 0;
218
219 memset(tb, 0, sizeof(tb));
220 netlink_parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
221
222 /* TBD: We don't care about rules not specifying an IIF. */
223 if (tb[FRA_IFNAME] == NULL)
224 return 0;
225
226 /* If we don't know the interface, we don't care. */
227 ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);
228 zns = zebra_ns_lookup(ns_id);
229 rule.ifp = if_lookup_by_name_per_ns(zns, ifname);
230 if (!rule.ifp)
231 return 0;
232
233 memset(&rule, 0, sizeof(rule));
234 if (tb[FRA_PRIORITY])
235 rule.rule.priority = *(uint32_t *)RTA_DATA(tb[FRA_PRIORITY]);
236
237 if (tb[FRA_SRC]) {
238 if (frh->family == AF_INET)
239 memcpy(&rule.rule.filter.src_ip.u.prefix4,
240 RTA_DATA(tb[FRA_SRC]), 4);
241 else
242 memcpy(&rule.rule.filter.src_ip.u.prefix6,
243 RTA_DATA(tb[FRA_SRC]), 16);
244 rule.rule.filter.src_ip.prefixlen = frh->src_len;
245 rule.rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
246 }
247
248 if (tb[FRA_DST]) {
249 if (frh->family == AF_INET)
250 memcpy(&rule.rule.filter.dst_ip.u.prefix4,
251 RTA_DATA(tb[FRA_DST]), 4);
252 else
253 memcpy(&rule.rule.filter.dst_ip.u.prefix6,
254 RTA_DATA(tb[FRA_DST]), 16);
255 rule.rule.filter.dst_ip.prefixlen = frh->dst_len;
256 rule.rule.filter.filter_bm |= PBR_FILTER_DST_IP;
257 }
258
259 if (tb[FRA_TABLE])
260 rule.rule.action.table = *(uint32_t *)RTA_DATA(tb[FRA_TABLE]);
261 else
262 rule.rule.action.table = frh->table;
263
264 if (IS_ZEBRA_DEBUG_KERNEL)
265 zlog_debug(
266 "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
267 nl_msg_type_to_str(h->nlmsg_type),
268 nl_family_to_str(frh->family), rule.ifp->name,
269 rule.ifp->ifindex, rule.rule.priority,
270 prefix2str(&rule.rule.filter.src_ip, buf1,
271 sizeof(buf1)),
272 prefix2str(&rule.rule.filter.dst_ip, buf2,
273 sizeof(buf2)),
274 rule.rule.action.table);
275
276 return kernel_pbr_rule_del(&rule);
277 }
278
279 /*
280 * Get to know existing PBR rules in the kernel - typically called at startup.
281 * TBD.
282 */
283 int netlink_rules_read(struct zebra_ns *zns)
284 {
285 return 0;
286 }
287
288 #endif /* HAVE_NETLINK */