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
)
61 struct fib_rule_hdr frh
;
62 char buf
[NL_PKT_BUF_SIZE
];
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
];
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);
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
;
78 req
.frh
.family
= family
;
79 req
.frh
.action
= FR_ACT_TO_TBL
;
82 addattr32(&req
.n
, sizeof(req
), FRA_PRIORITY
, rule
->rule
.priority
);
84 /* interface on which applied */
86 addattr_l(&req
.n
, sizeof(req
), FRA_IFNAME
, rule
->ifp
->name
,
87 strlen(rule
->ifp
->name
) + 1);
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
);
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
);
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
);
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
;
112 req
.frh
.table
= RT_TABLE_UNSPEC
;
113 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
,
114 rule
->rule
.action
.table
);
117 if (IS_ZEBRA_DEBUG_KERNEL
)
119 "Tx %s family %s IF %s(%u) Pref %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 prefix2str(&rule
->rule
.filter
.src_ip
, buf1
,
125 prefix2str(&rule
->rule
.filter
.dst_ip
, buf2
,
127 rule
->rule
.action
.table
);
129 /* Ship off the message.
130 * Note: Currently, netlink_talk() is a blocking call which returns
133 memset(&snl
, 0, sizeof(snl
));
134 snl
.nl_family
= AF_NETLINK
;
135 return netlink_talk(netlink_talk_filter
, &req
.n
,
136 &zns
->netlink_cmd
, zns
, 0);
140 /* Public functions */
142 * Install specified rule for a specific interface. The preference is what
143 * goes in the rule to denote relative ordering; it may or may not be the
144 * same as the rule's user-defined sequence number.
146 enum zebra_dplane_result
kernel_add_pbr_rule(struct zebra_pbr_rule
*rule
)
150 ret
= netlink_rule_update(RTM_NEWRULE
, rule
);
151 kernel_pbr_rule_add_del_status(rule
,
152 (!ret
) ? ZEBRA_DPLANE_INSTALL_SUCCESS
153 : ZEBRA_DPLANE_INSTALL_FAILURE
);
155 return ZEBRA_DPLANE_REQUEST_SUCCESS
;
159 * Uninstall specified rule for a specific interface.
161 enum zebra_dplane_result
kernel_del_pbr_rule(struct zebra_pbr_rule
*rule
)
165 ret
= netlink_rule_update(RTM_DELRULE
, rule
);
166 kernel_pbr_rule_add_del_status(rule
,
167 (!ret
) ? ZEBRA_DPLANE_DELETE_SUCCESS
168 : ZEBRA_DPLANE_DELETE_FAILURE
);
170 return ZEBRA_DPLANE_REQUEST_SUCCESS
;
174 * Handle netlink notification informing a rule add or delete.
175 * Handling of an ADD is TBD.
176 * DELs are notified up, if other attributes indicate it may be a
177 * notification of interest. The expectation is that if this corresponds
178 * to a PBR rule added by FRR, it will be readded.
180 int netlink_rule_change(struct nlmsghdr
*h
, ns_id_t ns_id
, int startup
)
182 struct zebra_ns
*zns
;
183 struct fib_rule_hdr
*frh
;
184 struct rtattr
*tb
[FRA_MAX
+ 1];
187 struct zebra_pbr_rule rule
;
188 char buf1
[PREFIX_STRLEN
];
189 char buf2
[PREFIX_STRLEN
];
191 /* Basic validation followed by extracting attributes. */
192 if (h
->nlmsg_type
!= RTM_NEWRULE
&& h
->nlmsg_type
!= RTM_DELRULE
)
196 if (h
->nlmsg_type
== RTM_NEWRULE
)
199 len
= h
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct fib_rule_hdr
));
201 zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
202 __PRETTY_FUNCTION__
, h
->nlmsg_len
,
203 (size_t)NLMSG_LENGTH(sizeof(struct fib_rule_hdr
)));
208 if (frh
->family
!= AF_INET
&& frh
->family
!= AF_INET6
) {
210 EC_ZEBRA_NETLINK_INVALID_AF
,
211 "Invalid address family: %u received from kernel rule change: %u",
212 frh
->family
, h
->nlmsg_type
);
215 if (frh
->action
!= FR_ACT_TO_TBL
)
218 memset(tb
, 0, sizeof(tb
));
219 netlink_parse_rtattr(tb
, FRA_MAX
, RTM_RTA(frh
), len
);
221 /* TBD: We don't care about rules not specifying an IIF. */
222 if (tb
[FRA_IFNAME
] == NULL
)
225 /* If we don't know the interface, we don't care. */
226 ifname
= (char *)RTA_DATA(tb
[FRA_IFNAME
]);
227 zns
= zebra_ns_lookup(ns_id
);
228 rule
.ifp
= if_lookup_by_name_per_ns(zns
, ifname
);
232 memset(&rule
, 0, sizeof(rule
));
233 if (tb
[FRA_PRIORITY
])
234 rule
.rule
.priority
= *(uint32_t *)RTA_DATA(tb
[FRA_PRIORITY
]);
237 if (frh
->family
== AF_INET
)
238 memcpy(&rule
.rule
.filter
.src_ip
.u
.prefix4
,
239 RTA_DATA(tb
[FRA_SRC
]), 4);
241 memcpy(&rule
.rule
.filter
.src_ip
.u
.prefix6
,
242 RTA_DATA(tb
[FRA_SRC
]), 16);
243 rule
.rule
.filter
.src_ip
.prefixlen
= frh
->src_len
;
244 rule
.rule
.filter
.filter_bm
|= PBR_FILTER_SRC_IP
;
248 if (frh
->family
== AF_INET
)
249 memcpy(&rule
.rule
.filter
.dst_ip
.u
.prefix4
,
250 RTA_DATA(tb
[FRA_DST
]), 4);
252 memcpy(&rule
.rule
.filter
.dst_ip
.u
.prefix6
,
253 RTA_DATA(tb
[FRA_DST
]), 16);
254 rule
.rule
.filter
.dst_ip
.prefixlen
= frh
->dst_len
;
255 rule
.rule
.filter
.filter_bm
|= PBR_FILTER_DST_IP
;
259 rule
.rule
.action
.table
= *(uint32_t *)RTA_DATA(tb
[FRA_TABLE
]);
261 rule
.rule
.action
.table
= frh
->table
;
263 if (IS_ZEBRA_DEBUG_KERNEL
)
265 "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
266 nl_msg_type_to_str(h
->nlmsg_type
),
267 nl_family_to_str(frh
->family
), rule
.ifp
->name
,
268 rule
.ifp
->ifindex
, rule
.rule
.priority
,
269 prefix2str(&rule
.rule
.filter
.src_ip
, buf1
,
271 prefix2str(&rule
.rule
.filter
.dst_ip
, buf2
,
273 rule
.rule
.action
.table
);
275 return kernel_pbr_rule_del(&rule
);
279 * Get to know existing PBR rules in the kernel - typically called at startup.
282 int netlink_rules_read(struct zebra_ns
*zns
)
287 #endif /* HAVE_NETLINK */