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 */
90 addattr_l(&req
.n
, sizeof(req
), FRA_IFNAME
, rule
->ifp
->name
,
91 strlen(rule
->ifp
->name
) + 1);
93 /* source IP, if specified */
94 if (IS_RULE_FILTERING_ON_SRC_IP(rule
)) {
95 req
.frh
.src_len
= rule
->rule
.filter
.src_ip
.prefixlen
;
96 addattr_l(&req
.n
, sizeof(req
), FRA_SRC
,
97 &rule
->rule
.filter
.src_ip
.u
.prefix
, bytelen
);
99 /* destination IP, if specified */
100 if (IS_RULE_FILTERING_ON_DST_IP(rule
)) {
101 req
.frh
.dst_len
= rule
->rule
.filter
.dst_ip
.prefixlen
;
102 addattr_l(&req
.n
, sizeof(req
), FRA_DST
,
103 &rule
->rule
.filter
.dst_ip
.u
.prefix
, bytelen
);
106 /* fwmark, if specified */
107 if (IS_RULE_FILTERING_ON_FWMARK(rule
)) {
108 addattr32(&req
.n
, sizeof(req
), FRA_FWMARK
,
109 rule
->rule
.filter
.fwmark
);
112 /* Route table to use to forward, if filter criteria matches. */
113 if (rule
->rule
.action
.table
< 256)
114 req
.frh
.table
= rule
->rule
.action
.table
;
116 req
.frh
.table
= RT_TABLE_UNSPEC
;
117 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
,
118 rule
->rule
.action
.table
);
121 if (IS_ZEBRA_DEBUG_KERNEL
)
123 "Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u",
124 nl_msg_type_to_str(cmd
), nl_family_to_str(family
),
125 rule
->ifp
? rule
->ifp
->name
: "Unknown",
126 rule
->ifp
? rule
->ifp
->ifindex
: 0, rule
->rule
.priority
,
127 rule
->rule
.filter
.fwmark
,
128 prefix2str(&rule
->rule
.filter
.src_ip
, buf1
,
130 prefix2str(&rule
->rule
.filter
.dst_ip
, buf2
,
132 rule
->rule
.action
.table
);
134 /* Ship off the message.
135 * Note: Currently, netlink_talk() is a blocking call which returns
138 memset(&snl
, 0, sizeof(snl
));
139 snl
.nl_family
= AF_NETLINK
;
140 return netlink_talk(netlink_talk_filter
, &req
.n
,
141 &zns
->netlink_cmd
, zns
, 0);
145 /* Public functions */
147 * Install specified rule for a specific interface. The preference is what
148 * goes in the rule to denote relative ordering; it may or may not be the
149 * same as the rule's user-defined sequence number.
151 enum zebra_dplane_result
kernel_add_pbr_rule(struct zebra_pbr_rule
*rule
)
155 ret
= netlink_rule_update(RTM_NEWRULE
, rule
);
156 kernel_pbr_rule_add_del_status(rule
,
157 (!ret
) ? ZEBRA_DPLANE_INSTALL_SUCCESS
158 : ZEBRA_DPLANE_INSTALL_FAILURE
);
160 return ZEBRA_DPLANE_REQUEST_SUCCESS
;
164 * Uninstall specified rule for a specific interface.
166 enum zebra_dplane_result
kernel_del_pbr_rule(struct zebra_pbr_rule
*rule
)
170 ret
= netlink_rule_update(RTM_DELRULE
, rule
);
171 kernel_pbr_rule_add_del_status(rule
,
172 (!ret
) ? ZEBRA_DPLANE_DELETE_SUCCESS
173 : ZEBRA_DPLANE_DELETE_FAILURE
);
175 return ZEBRA_DPLANE_REQUEST_SUCCESS
;
179 * Handle netlink notification informing a rule add or delete.
180 * Handling of an ADD is TBD.
181 * DELs are notified up, if other attributes indicate it may be a
182 * notification of interest. The expectation is that if this corresponds
183 * to a PBR rule added by FRR, it will be readded.
185 int netlink_rule_change(struct nlmsghdr
*h
, ns_id_t ns_id
, int startup
)
187 struct zebra_ns
*zns
;
188 struct fib_rule_hdr
*frh
;
189 struct rtattr
*tb
[FRA_MAX
+ 1];
192 struct zebra_pbr_rule rule
= {};
193 char buf1
[PREFIX_STRLEN
];
194 char buf2
[PREFIX_STRLEN
];
196 /* Basic validation followed by extracting attributes. */
197 if (h
->nlmsg_type
!= RTM_NEWRULE
&& h
->nlmsg_type
!= RTM_DELRULE
)
201 if (h
->nlmsg_type
== RTM_NEWRULE
)
204 len
= h
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct fib_rule_hdr
));
206 zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
207 __PRETTY_FUNCTION__
, h
->nlmsg_len
,
208 (size_t)NLMSG_LENGTH(sizeof(struct fib_rule_hdr
)));
213 if (frh
->family
!= AF_INET
&& frh
->family
!= AF_INET6
) {
215 EC_ZEBRA_NETLINK_INVALID_AF
,
216 "Invalid address family: %u received from kernel rule change: %u",
217 frh
->family
, h
->nlmsg_type
);
220 if (frh
->action
!= FR_ACT_TO_TBL
)
223 memset(tb
, 0, sizeof(tb
));
224 netlink_parse_rtattr(tb
, FRA_MAX
, RTM_RTA(frh
), len
);
226 /* TBD: We don't care about rules not specifying an IIF. */
227 if (tb
[FRA_IFNAME
] == NULL
)
230 /* If we don't know the interface, we don't care. */
231 ifname
= (char *)RTA_DATA(tb
[FRA_IFNAME
]);
232 zns
= zebra_ns_lookup(ns_id
);
233 rule
.ifp
= if_lookup_by_name_per_ns(zns
, 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
.ifp
->name
,
272 rule
.ifp
->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 */