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