]>
git.proxmox.com Git - mirror_frr.git/blob - zebra/rule_netlink.c
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"
46 /* static function declarations */
48 /* Private functions */
50 /* Install or uninstall specified rule for a specific interface.
51 * Form netlink message and ship it. Currently, notify status after
52 * waiting for netlink status.
54 static int netlink_rule_update(int cmd
, struct zebra_pbr_rule
*rule
)
60 struct fib_rule_hdr frh
;
61 char buf
[NL_PKT_BUF_SIZE
];
63 struct zebra_ns
*zns
= zebra_ns_lookup(NS_DEFAULT
);
64 struct sockaddr_nl snl
;
65 char buf1
[PREFIX_STRLEN
];
66 char buf2
[PREFIX_STRLEN
];
68 memset(&req
, 0, sizeof(req
) - NL_PKT_BUF_SIZE
);
69 family
= PREFIX_FAMILY(&rule
->rule
.filter
.src_ip
);
70 bytelen
= (family
== AF_INET
? 4 : 16);
72 req
.n
.nlmsg_type
= cmd
;
73 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
74 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
75 req
.n
.nlmsg_pid
= zns
->netlink_cmd
.snl
.nl_pid
;
77 req
.frh
.family
= family
;
78 req
.frh
.action
= FR_ACT_TO_TBL
;
81 addattr32(&req
.n
, sizeof(req
), FRA_PRIORITY
, rule
->rule
.priority
);
83 /* interface on which applied */
85 addattr_l(&req
.n
, sizeof(req
), FRA_IFNAME
, rule
->ifp
->name
,
86 strlen(rule
->ifp
->name
) + 1);
88 /* source IP, if specified */
89 if (IS_RULE_FILTERING_ON_SRC_IP(rule
)) {
90 req
.frh
.src_len
= rule
->rule
.filter
.src_ip
.prefixlen
;
91 addattr_l(&req
.n
, sizeof(req
), FRA_SRC
,
92 &rule
->rule
.filter
.src_ip
.u
.prefix
, bytelen
);
94 /* destination IP, if specified */
95 if (IS_RULE_FILTERING_ON_DST_IP(rule
)) {
96 req
.frh
.dst_len
= rule
->rule
.filter
.dst_ip
.prefixlen
;
97 addattr_l(&req
.n
, sizeof(req
), FRA_DST
,
98 &rule
->rule
.filter
.dst_ip
.u
.prefix
, bytelen
);
101 /* fwmark, if specified */
102 if (IS_RULE_FILTERING_ON_FWMARK(rule
)) {
103 addattr32(&req
.n
, sizeof(req
), FRA_FWMARK
,
104 rule
->rule
.filter
.fwmark
);
107 /* Route table to use to forward, if filter criteria matches. */
108 if (rule
->rule
.action
.table
< 256)
109 req
.frh
.table
= rule
->rule
.action
.table
;
111 req
.frh
.table
= RT_TABLE_UNSPEC
;
112 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
,
113 rule
->rule
.action
.table
);
116 if (IS_ZEBRA_DEBUG_KERNEL
)
118 "Tx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
119 nl_msg_type_to_str(cmd
), nl_family_to_str(family
),
120 rule
->ifp
? rule
->ifp
->name
: "Unknown",
121 rule
->ifp
? rule
->ifp
->ifindex
: 0, rule
->rule
.priority
,
122 prefix2str(&rule
->rule
.filter
.src_ip
, buf1
,
124 prefix2str(&rule
->rule
.filter
.dst_ip
, buf2
,
126 rule
->rule
.action
.table
);
128 /* Ship off the message.
129 * Note: Currently, netlink_talk() is a blocking call which returns
132 memset(&snl
, 0, sizeof(snl
));
133 snl
.nl_family
= AF_NETLINK
;
134 return netlink_talk(netlink_talk_filter
, &req
.n
,
135 &zns
->netlink_cmd
, zns
, 0);
139 /* Public functions */
141 * Install specified rule for a specific interface. The preference is what
142 * goes in the rule to denote relative ordering; it may or may not be the
143 * same as the rule's user-defined sequence number.
145 enum dp_req_result
kernel_add_pbr_rule(struct zebra_pbr_rule
*rule
)
149 ret
= netlink_rule_update(RTM_NEWRULE
, rule
);
150 kernel_pbr_rule_add_del_status(rule
,
151 (!ret
) ? DP_INSTALL_SUCCESS
152 : DP_INSTALL_FAILURE
);
154 return DP_REQUEST_SUCCESS
;
158 * Uninstall specified rule for a specific interface.
160 enum dp_req_result
kernel_del_pbr_rule(struct zebra_pbr_rule
*rule
)
164 ret
= netlink_rule_update(RTM_DELRULE
, rule
);
165 kernel_pbr_rule_add_del_status(rule
,
166 (!ret
) ? DP_DELETE_SUCCESS
167 : DP_DELETE_FAILURE
);
169 return DP_REQUEST_SUCCESS
;
173 * Handle netlink notification informing a rule add or delete.
174 * Handling of an ADD is TBD.
175 * DELs are notified up, if other attributes indicate it may be a
176 * notification of interest. The expectation is that if this corresponds
177 * to a PBR rule added by FRR, it will be readded.
179 int netlink_rule_change(struct nlmsghdr
*h
, ns_id_t ns_id
, int startup
)
181 struct zebra_ns
*zns
;
182 struct fib_rule_hdr
*frh
;
183 struct rtattr
*tb
[FRA_MAX
+ 1];
186 struct zebra_pbr_rule rule
;
187 char buf1
[PREFIX_STRLEN
];
188 char buf2
[PREFIX_STRLEN
];
190 /* Basic validation followed by extracting attributes. */
191 if (h
->nlmsg_type
!= RTM_NEWRULE
&& h
->nlmsg_type
!= RTM_DELRULE
)
195 if (h
->nlmsg_type
== RTM_NEWRULE
)
198 len
= h
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct fib_rule_hdr
));
200 zlog_err("%s: Message received from netlink is of a broken size: %d %zu",
201 __PRETTY_FUNCTION__
, h
->nlmsg_len
,
202 (size_t)NLMSG_LENGTH(sizeof(struct fib_rule_hdr
)));
207 if (frh
->family
!= AF_INET
&& frh
->family
!= AF_INET6
)
209 if (frh
->action
!= FR_ACT_TO_TBL
)
212 memset(tb
, 0, sizeof(tb
));
213 netlink_parse_rtattr(tb
, FRA_MAX
, RTM_RTA(frh
), len
);
215 /* TBD: We don't care about rules not specifying an IIF. */
216 if (tb
[FRA_IFNAME
] == NULL
)
219 /* If we don't know the interface, we don't care. */
220 ifname
= (char *)RTA_DATA(tb
[FRA_IFNAME
]);
221 zns
= zebra_ns_lookup(ns_id
);
222 rule
.ifp
= if_lookup_by_name_per_ns(zns
, ifname
);
226 memset(&rule
, 0, sizeof(rule
));
227 if (tb
[FRA_PRIORITY
])
228 rule
.rule
.priority
= *(uint32_t *)RTA_DATA(tb
[FRA_PRIORITY
]);
231 if (frh
->family
== AF_INET
)
232 memcpy(&rule
.rule
.filter
.src_ip
.u
.prefix4
,
233 RTA_DATA(tb
[FRA_SRC
]), 4);
235 memcpy(&rule
.rule
.filter
.src_ip
.u
.prefix6
,
236 RTA_DATA(tb
[FRA_SRC
]), 16);
237 rule
.rule
.filter
.src_ip
.prefixlen
= frh
->src_len
;
238 rule
.rule
.filter
.filter_bm
|= PBR_FILTER_SRC_IP
;
242 if (frh
->family
== AF_INET
)
243 memcpy(&rule
.rule
.filter
.dst_ip
.u
.prefix4
,
244 RTA_DATA(tb
[FRA_DST
]), 4);
246 memcpy(&rule
.rule
.filter
.dst_ip
.u
.prefix6
,
247 RTA_DATA(tb
[FRA_DST
]), 16);
248 rule
.rule
.filter
.dst_ip
.prefixlen
= frh
->dst_len
;
249 rule
.rule
.filter
.filter_bm
|= PBR_FILTER_DST_IP
;
253 rule
.rule
.action
.table
= *(uint32_t *)RTA_DATA(tb
[FRA_TABLE
]);
255 rule
.rule
.action
.table
= frh
->table
;
257 if (IS_ZEBRA_DEBUG_KERNEL
)
259 "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
260 nl_msg_type_to_str(h
->nlmsg_type
),
261 nl_family_to_str(frh
->family
), rule
.ifp
->name
,
262 rule
.ifp
->ifindex
, rule
.rule
.priority
,
263 prefix2str(&rule
.rule
.filter
.src_ip
, buf1
,
265 prefix2str(&rule
.rule
.filter
.dst_ip
, buf2
,
267 rule
.rule
.action
.table
);
269 return kernel_pbr_rule_del(&rule
);
273 * Get to know existing PBR rules in the kernel - typically called at startup.
276 int netlink_rules_read(struct zebra_ns
*zns
)
281 #endif /* HAVE_NETLINK */