2 * Zebra Policy Based Routing (PBR) interaction with the kernel using
4 * Copyright (C) 2018 Cumulus Networks, Inc.
6 * This file is part of FRR.
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
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.
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
32 #include <linux/fib_rules.h>
33 #include "zebra/zserv.h"
34 #include "zebra/zebra_ns.h"
35 #include "zebra/zebra_vrf.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"
47 /* static function declarations */
49 /* Private functions */
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.
55 static int netlink_rule_update(int cmd
, struct zebra_pbr_rule
*rule
)
57 uint8_t protocol
= RTPROT_ZEBRA
;
62 struct fib_rule_hdr frh
;
63 char buf
[NL_PKT_BUF_SIZE
];
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
];
70 memset(&req
, 0, sizeof(req
) - NL_PKT_BUF_SIZE
);
71 family
= PREFIX_FAMILY(&rule
->rule
.filter
.src_ip
);
72 bytelen
= (family
== AF_INET
? 4 : 16);
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
;
79 req
.frh
.family
= family
;
80 req
.frh
.action
= FR_ACT_TO_TBL
;
82 addattr_l(&req
.n
, sizeof(req
),
83 FRA_PROTOCOL
, &protocol
, sizeof(protocol
));
86 addattr32(&req
.n
, sizeof(req
), FRA_PRIORITY
, rule
->rule
.priority
);
88 /* interface on which applied */
89 addattr_l(&req
.n
, sizeof(req
), FRA_IFNAME
, rule
->ifname
,
90 strlen(rule
->ifname
) + 1);
92 /* source IP, if specified */
93 if (IS_RULE_FILTERING_ON_SRC_IP(rule
)) {
94 req
.frh
.src_len
= rule
->rule
.filter
.src_ip
.prefixlen
;
95 addattr_l(&req
.n
, sizeof(req
), FRA_SRC
,
96 &rule
->rule
.filter
.src_ip
.u
.prefix
, bytelen
);
98 /* destination IP, if specified */
99 if (IS_RULE_FILTERING_ON_DST_IP(rule
)) {
100 req
.frh
.dst_len
= rule
->rule
.filter
.dst_ip
.prefixlen
;
101 addattr_l(&req
.n
, sizeof(req
), FRA_DST
,
102 &rule
->rule
.filter
.dst_ip
.u
.prefix
, bytelen
);
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
);
111 /* Route table to use to forward, if filter criteria matches. */
112 if (rule
->rule
.action
.table
< 256)
113 req
.frh
.table
= rule
->rule
.action
.table
;
115 req
.frh
.table
= RT_TABLE_UNSPEC
;
116 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
,
117 rule
->rule
.action
.table
);
120 if (IS_ZEBRA_DEBUG_KERNEL
)
122 "Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u",
123 nl_msg_type_to_str(cmd
), nl_family_to_str(family
),
124 rule
->ifname
, rule
->rule
.ifindex
, rule
->rule
.priority
,
125 rule
->rule
.filter
.fwmark
,
126 prefix2str(&rule
->rule
.filter
.src_ip
, buf1
,
128 prefix2str(&rule
->rule
.filter
.dst_ip
, buf2
,
130 rule
->rule
.action
.table
);
132 /* Ship off the message.
133 * Note: Currently, netlink_talk() is a blocking call which returns
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);
143 /* Public functions */
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.
149 enum zebra_dplane_result
kernel_add_pbr_rule(struct zebra_pbr_rule
*rule
)
153 ret
= netlink_rule_update(RTM_NEWRULE
, rule
);
154 kernel_pbr_rule_add_del_status(rule
,
155 (!ret
) ? ZEBRA_DPLANE_INSTALL_SUCCESS
156 : ZEBRA_DPLANE_INSTALL_FAILURE
);
158 return ZEBRA_DPLANE_REQUEST_SUCCESS
;
162 * Uninstall specified rule for a specific interface.
164 enum zebra_dplane_result
kernel_del_pbr_rule(struct zebra_pbr_rule
*rule
)
168 ret
= netlink_rule_update(RTM_DELRULE
, rule
);
169 kernel_pbr_rule_add_del_status(rule
,
170 (!ret
) ? ZEBRA_DPLANE_DELETE_SUCCESS
171 : ZEBRA_DPLANE_DELETE_FAILURE
);
173 return ZEBRA_DPLANE_REQUEST_SUCCESS
;
177 * Handle netlink notification informing a rule add or delete.
178 * Handling of an ADD is TBD.
179 * DELs are notified up, if other attributes indicate it may be a
180 * notification of interest. The expectation is that if this corresponds
181 * to a PBR rule added by FRR, it will be readded.
183 int netlink_rule_change(struct nlmsghdr
*h
, ns_id_t ns_id
, int startup
)
185 struct zebra_ns
*zns
;
186 struct fib_rule_hdr
*frh
;
187 struct rtattr
*tb
[FRA_MAX
+ 1];
190 struct zebra_pbr_rule rule
= {};
191 char buf1
[PREFIX_STRLEN
];
192 char buf2
[PREFIX_STRLEN
];
194 /* Basic validation followed by extracting attributes. */
195 if (h
->nlmsg_type
!= RTM_NEWRULE
&& h
->nlmsg_type
!= RTM_DELRULE
)
199 if (h
->nlmsg_type
== RTM_NEWRULE
)
202 len
= h
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct fib_rule_hdr
));
204 zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
205 __PRETTY_FUNCTION__
, h
->nlmsg_len
,
206 (size_t)NLMSG_LENGTH(sizeof(struct fib_rule_hdr
)));
211 if (frh
->family
!= AF_INET
&& frh
->family
!= AF_INET6
) {
213 EC_ZEBRA_NETLINK_INVALID_AF
,
214 "Invalid address family: %u received from kernel rule change: %u",
215 frh
->family
, h
->nlmsg_type
);
218 if (frh
->action
!= FR_ACT_TO_TBL
)
221 memset(tb
, 0, sizeof(tb
));
222 netlink_parse_rtattr(tb
, FRA_MAX
, RTM_RTA(frh
), len
);
224 /* TBD: We don't care about rules not specifying an IIF. */
225 if (tb
[FRA_IFNAME
] == NULL
)
228 ifname
= (char *)RTA_DATA(tb
[FRA_IFNAME
]);
229 zns
= zebra_ns_lookup(ns_id
);
231 /* If we don't know the interface, we don't care. */
232 if (!if_lookup_by_name_per_ns(zns
, ifname
))
235 strlcpy(rule
.ifname
, ifname
, sizeof(rule
.ifname
));
237 if (tb
[FRA_PRIORITY
])
238 rule
.rule
.priority
= *(uint32_t *)RTA_DATA(tb
[FRA_PRIORITY
]);
241 if (frh
->family
== AF_INET
)
242 memcpy(&rule
.rule
.filter
.src_ip
.u
.prefix4
,
243 RTA_DATA(tb
[FRA_SRC
]), 4);
245 memcpy(&rule
.rule
.filter
.src_ip
.u
.prefix6
,
246 RTA_DATA(tb
[FRA_SRC
]), 16);
247 rule
.rule
.filter
.src_ip
.prefixlen
= frh
->src_len
;
248 rule
.rule
.filter
.filter_bm
|= PBR_FILTER_SRC_IP
;
252 if (frh
->family
== AF_INET
)
253 memcpy(&rule
.rule
.filter
.dst_ip
.u
.prefix4
,
254 RTA_DATA(tb
[FRA_DST
]), 4);
256 memcpy(&rule
.rule
.filter
.dst_ip
.u
.prefix6
,
257 RTA_DATA(tb
[FRA_DST
]), 16);
258 rule
.rule
.filter
.dst_ip
.prefixlen
= frh
->dst_len
;
259 rule
.rule
.filter
.filter_bm
|= PBR_FILTER_DST_IP
;
263 rule
.rule
.action
.table
= *(uint32_t *)RTA_DATA(tb
[FRA_TABLE
]);
265 rule
.rule
.action
.table
= frh
->table
;
267 if (IS_ZEBRA_DEBUG_KERNEL
)
269 "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
270 nl_msg_type_to_str(h
->nlmsg_type
),
271 nl_family_to_str(frh
->family
), rule
.ifname
,
272 rule
.rule
.ifindex
, rule
.rule
.priority
,
273 prefix2str(&rule
.rule
.filter
.src_ip
, buf1
,
275 prefix2str(&rule
.rule
.filter
.dst_ip
, buf2
,
277 rule
.rule
.action
.table
);
279 return kernel_pbr_rule_del(&rule
);
283 * Get to know existing PBR rules in the kernel - typically called at startup.
286 int netlink_rules_read(struct zebra_ns
*zns
)
291 #endif /* HAVE_NETLINK */