20 #include <netlink-private/netlink.h> 21 #include <netlink/netlink.h> 22 #include <netlink/utils.h> 23 #include <netlink/route/netconf.h> 24 #include <linux/netconf.h> 25 #include <linux/socket.h> 26 #include <netlink/hashtable.h> 29 #define NETCONF_ATTR_FAMILY 0x0001 30 #define NETCONF_ATTR_IFINDEX 0x0002 31 #define NETCONF_ATTR_RP_FILTER 0x0004 32 #define NETCONF_ATTR_FWDING 0x0008 33 #define NETCONF_ATTR_MC_FWDING 0x0010 34 #define NETCONF_ATTR_PROXY_NEIGH 0x0020 35 #define NETCONF_ATTR_IGNORE_RT_LINKDWN 0x0040 36 #define NETCONF_ATTR_INPUT 0x0080 48 int ignore_routes_linkdown;
52 static struct nl_cache_ops rtnl_netconf_ops;
53 static struct nl_object_ops netconf_obj_ops;
56 static struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
57 [NETCONFA_IFINDEX] = { .
type = NLA_S32 },
58 [NETCONFA_FORWARDING] = { .type = NLA_S32 },
59 [NETCONFA_MC_FORWARDING] = { .type = NLA_S32 },
60 [NETCONFA_RP_FILTER] = { .type = NLA_S32 },
61 [NETCONFA_PROXY_NEIGH] = { .type = NLA_S32 },
62 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .type = NLA_S32 },
65 static struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = {
66 [NETCONFA_IFINDEX] = { .
type = NLA_S32 },
67 [NETCONFA_FORWARDING] = { .type = NLA_S32 },
68 [NETCONFA_MC_FORWARDING] = { .type = NLA_S32 },
69 [NETCONFA_PROXY_NEIGH] = { .type = NLA_S32 },
70 [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .type = NLA_S32 },
73 static struct nla_policy devconf_mpls_policy[NETCONFA_MAX+1] = {
74 [NETCONFA_IFINDEX] = { .
type = NLA_S32 },
75 [NETCONFA_INPUT] = { .type = NLA_S32 },
78 static struct rtnl_netconf *rtnl_netconf_alloc(
void)
83 static int netconf_clone(
struct nl_object *_dst,
struct nl_object *_src)
85 struct rtnl_netconf *dst = nl_object_priv(_dst);
86 struct rtnl_netconf *src = nl_object_priv(_src);
93 static int netconf_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
94 struct nlmsghdr *nlh,
struct nl_parser_param *pp)
96 struct nlattr *tb[NETCONFA_MAX+1], *attr;
97 struct rtnl_netconf *nc;
98 struct netconfmsg *ncm;
102 switch (ncm->ncm_family) {
104 err =
nlmsg_parse(nlh,
sizeof(*ncm), tb, NETCONFA_MAX,
105 devconf_ipv4_policy);
110 err =
nlmsg_parse(nlh,
sizeof(*ncm), tb, NETCONFA_MAX,
111 devconf_ipv6_policy);
116 err =
nlmsg_parse(nlh,
sizeof(*ncm), tb, NETCONFA_MAX,
117 devconf_mpls_policy);
122 printf(
"unexpected netconf family: %d\n", ncm->ncm_family);
126 if (!tb[NETCONFA_IFINDEX])
129 nc = rtnl_netconf_alloc();
133 nc->ce_msgtype = nlh->nlmsg_type;
134 nc->family = ncm->ncm_family;
137 nc->ce_mask = NETCONF_ATTR_FAMILY | NETCONF_ATTR_IFINDEX;
140 if (tb[NETCONFA_RP_FILTER]) {
141 attr = tb[NETCONFA_RP_FILTER];
143 nc->ce_mask |= NETCONF_ATTR_RP_FILTER;
146 if (tb[NETCONFA_FORWARDING]) {
147 attr = tb[NETCONFA_FORWARDING];
149 nc->ce_mask |= NETCONF_ATTR_FWDING;
152 if (tb[NETCONFA_MC_FORWARDING]) {
153 attr = tb[NETCONFA_MC_FORWARDING];
155 nc->ce_mask |= NETCONF_ATTR_MC_FWDING;
158 if (tb[NETCONFA_PROXY_NEIGH]) {
159 attr = tb[NETCONFA_PROXY_NEIGH];
161 nc->ce_mask |= NETCONF_ATTR_PROXY_NEIGH;
164 if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) {
165 attr = tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN];
167 nc->ce_mask |= NETCONF_ATTR_IGNORE_RT_LINKDWN;
170 if (tb[NETCONFA_INPUT]) {
171 attr = tb[NETCONFA_INPUT];
173 nc->ce_mask |= NETCONF_ATTR_INPUT;
176 err = pp->pp_cb((
struct nl_object *) nc, pp);
178 rtnl_netconf_put(nc);
182 static int netconf_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
184 struct netconfmsg nc = {
185 .ncm_family = cache->c_iarg1,
188 return nl_send_simple(sk, RTM_GETNETCONF, NLM_F_DUMP, &nc,
sizeof(nc));
191 static void netconf_dump_line(
struct nl_object *obj,
struct nl_dump_params *p)
193 struct rtnl_netconf *nc = (
struct rtnl_netconf *) obj;
194 struct nl_cache *link_cache;
211 switch(nc->ifindex) {
212 case NETCONFA_IFINDEX_ALL:
215 case NETCONFA_IFINDEX_DEFAULT:
224 nl_cache_put(link_cache);
226 nl_dump(p,
"dev %d ", nc->ifindex);
229 if (nc->ce_mask & NETCONF_ATTR_FWDING) {
231 nc->forwarding ?
"on" :
"off");
234 if (nc->ce_mask & NETCONF_ATTR_RP_FILTER) {
235 if (nc->rp_filter == 0)
237 else if (nc->rp_filter == 1)
238 nl_dump(p,
"rp_filter strict ");
239 else if (nc->rp_filter == 2)
240 nl_dump(p,
"rp_filter loose ");
242 nl_dump(p,
"rp_filter unknown-mode ");
245 if (nc->ce_mask & NETCONF_ATTR_MC_FWDING) {
246 nl_dump(p,
"mc_forwarding %s ",
247 nc->mc_forwarding ?
"on" :
"off");
250 if (nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH)
251 nl_dump(p,
"proxy_neigh %d ", nc->proxy_neigh);
253 if (nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN) {
254 nl_dump(p,
"ignore_routes_with_linkdown %s ",
255 nc->ignore_routes_linkdown ?
"on" :
"off");
258 if (nc->ce_mask & NETCONF_ATTR_INPUT)
259 nl_dump(p,
"input %s ", nc->input ?
"on" :
"off");
264 static const struct trans_tbl netconf_attrs[] = {
265 __ADD(NETCONF_ATTR_FAMILY, family),
266 __ADD(NETCONF_ATTR_IFINDEX, ifindex),
267 __ADD(NETCONF_ATTR_RP_FILTER, rp_filter),
268 __ADD(NETCONF_ATTR_FWDING, forwarding),
269 __ADD(NETCONF_ATTR_MC_FWDING, mc_forwarding),
270 __ADD(NETCONF_ATTR_PROXY_NEIGH, proxy_neigh),
271 __ADD(NETCONF_ATTR_IGNORE_RT_LINKDWN, ignore_routes_with_linkdown),
272 __ADD(NETCONF_ATTR_INPUT, input),
275 static char *netconf_attrs2str(
int attrs,
char *buf,
size_t len)
277 return __flags2str(attrs, buf, len, netconf_attrs,
278 ARRAY_SIZE(netconf_attrs));
281 static void netconf_keygen(
struct nl_object *obj, uint32_t *hashkey,
284 struct rtnl_netconf *nc = (
struct rtnl_netconf *) obj;
285 unsigned int nckey_sz;
289 } __attribute__((packed)) nckey;
291 nckey_sz =
sizeof(nckey);
292 nckey.nc_family = nc->family;
293 nckey.nc_index = nc->ifindex;
295 *hashkey = nl_hash(&nckey, nckey_sz, 0) % table_sz;
297 NL_DBG(5,
"netconf %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
298 nc, nckey.nc_index, nckey.nc_family, nckey_sz, *hashkey);
301 static uint64_t netconf_compare(
struct nl_object *_a,
struct nl_object *_b,
302 uint64_t attrs,
int flags)
304 struct rtnl_netconf *a = (
struct rtnl_netconf *) _a;
305 struct rtnl_netconf *b = (
struct rtnl_netconf *) _b;
308 #define NETCONF_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NETCONF_ATTR_##ATTR, a, b, EXPR) 310 diff |= NETCONF_DIFF(FAMILY, a->family != b->family);
311 diff |= NETCONF_DIFF(IFINDEX, a->ifindex != b->ifindex);
312 diff |= NETCONF_DIFF(RP_FILTER, a->rp_filter != b->rp_filter);
313 diff |= NETCONF_DIFF(FWDING, a->forwarding != b->forwarding);
314 diff |= NETCONF_DIFF(MC_FWDING, a->mc_forwarding != b->mc_forwarding);
315 diff |= NETCONF_DIFF(PROXY_NEIGH, a->proxy_neigh != b->proxy_neigh);
316 diff |= NETCONF_DIFF(IGNORE_RT_LINKDWN,
317 a->ignore_routes_linkdown != b->ignore_routes_linkdown);
318 diff |= NETCONF_DIFF(INPUT, a->input != b->input);
325 static int netconf_update(
struct nl_object *old_obj,
struct nl_object *new_obj)
327 struct rtnl_netconf *new_nc = (
struct rtnl_netconf *) new_obj;
328 struct rtnl_netconf *old_nc = (
struct rtnl_netconf *) old_obj;
329 int action = new_obj->ce_msgtype;
333 if (new_nc->family != old_nc->family ||
334 new_nc->ifindex != old_nc->ifindex)
335 return -NLE_OPNOTSUPP;
337 if (new_nc->ce_mask & NETCONF_ATTR_RP_FILTER)
338 old_nc->rp_filter = new_nc->rp_filter;
339 if (new_nc->ce_mask & NETCONF_ATTR_FWDING)
340 old_nc->forwarding = new_nc->forwarding;
341 if (new_nc->ce_mask & NETCONF_ATTR_MC_FWDING)
342 old_nc->mc_forwarding = new_nc->mc_forwarding;
343 if (new_nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH)
344 old_nc->proxy_neigh = new_nc->proxy_neigh;
345 if (new_nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN)
346 old_nc->ignore_routes_linkdown = new_nc->ignore_routes_linkdown;
350 return -NLE_OPNOTSUPP;
361 int rtnl_netconf_alloc_cache(
struct nl_sock *sk,
struct nl_cache **result)
384 struct rtnl_netconf *nc;
386 if (!ifindex || !family || cache->c_ops != &rtnl_netconf_ops)
389 nl_list_for_each_entry(nc, &cache->c_items, ce_list) {
390 if (nc->ifindex == ifindex &&
391 nc->family == family) {
400 void rtnl_netconf_put(
struct rtnl_netconf *nc)
450 int rtnl_netconf_get_family(
struct rtnl_netconf *nc,
int *val)
454 if (!(nc->ce_mask & NETCONF_ATTR_FAMILY))
455 return -NLE_MISSING_ATTR;
460 int rtnl_netconf_get_ifindex(
struct rtnl_netconf *nc,
int *val)
464 if (!(nc->ce_mask & NETCONF_ATTR_IFINDEX))
465 return -NLE_MISSING_ATTR;
470 int rtnl_netconf_get_forwarding(
struct rtnl_netconf *nc,
int *val)
474 if (!(nc->ce_mask & NETCONF_ATTR_FWDING))
475 return -NLE_MISSING_ATTR;
477 *val = nc->forwarding;
480 int rtnl_netconf_get_mc_forwarding(
struct rtnl_netconf *nc,
int *val)
484 if (!(nc->ce_mask & NETCONF_ATTR_MC_FWDING))
485 return -NLE_MISSING_ATTR;
487 *val = nc->mc_forwarding;
490 int rtnl_netconf_get_rp_filter(
struct rtnl_netconf *nc,
int *val)
494 if (!(nc->ce_mask & NETCONF_ATTR_RP_FILTER))
495 return -NLE_MISSING_ATTR;
497 *val = nc->rp_filter;
500 int rtnl_netconf_get_proxy_neigh(
struct rtnl_netconf *nc,
int *val)
504 if (!(nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH))
505 return -NLE_MISSING_ATTR;
507 *val = nc->proxy_neigh;
510 int rtnl_netconf_get_ignore_routes_linkdown(
struct rtnl_netconf *nc,
int *val)
514 if (!(nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN))
515 return -NLE_MISSING_ATTR;
517 *val = nc->ignore_routes_linkdown;
520 int rtnl_netconf_get_input(
struct rtnl_netconf *nc,
int *val)
524 if (!(nc->ce_mask & NETCONF_ATTR_INPUT))
525 return -NLE_MISSING_ATTR;
534 static struct nl_object_ops netconf_obj_ops = {
535 .oo_name =
"route/netconf",
536 .oo_size =
sizeof(
struct rtnl_netconf),
537 .oo_clone = netconf_clone,
542 .oo_compare = netconf_compare,
543 .oo_keygen = netconf_keygen,
544 .oo_update = netconf_update,
545 .oo_attrs2str = netconf_attrs2str,
546 .oo_id_attrs = (NETCONF_ATTR_FAMILY |
547 NETCONF_ATTR_IFINDEX)
550 static struct nl_af_group netconf_groups[] = {
551 { AF_INET, RTNLGRP_IPV4_NETCONF },
552 { AF_INET6, RTNLGRP_IPV6_NETCONF },
553 { AF_MPLS, RTNLGRP_MPLS_NETCONF },
554 { END_OF_GROUP_LIST },
557 static struct nl_cache_ops rtnl_netconf_ops = {
558 .co_name =
"route/netconf",
559 .co_hdrsize =
sizeof(
struct netconfmsg),
561 { RTM_NEWNETCONF, NL_ACT_NEW,
"new" },
562 { RTM_DELNETCONF, NL_ACT_DEL,
"del" },
563 { RTM_GETNETCONF, NL_ACT_GET,
"get" },
564 END_OF_MSGTYPES_LIST,
566 .co_protocol = NETLINK_ROUTE,
567 .co_groups = netconf_groups,
568 .co_request_update = netconf_request_update,
569 .co_msg_parser = netconf_msg_parser,
570 .co_obj_ops = &netconf_obj_ops,
573 static void __init netconf_init(
void)
578 static void __exit netconf_exit(
void)
Dump object briefly on one line.
int32_t nla_get_s32(const struct nlattr *nla)
Return payload of 32 bit signed integer attribute.
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Attribute validation policy.
struct nl_cache * nl_cache_mngt_require_safe(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, struct nla_policy *policy)
parse attributes of a netlink message
struct rtnl_netconf * rtnl_netconf_get_by_idx(struct nl_cache *cache, int family, int ifindex)
Search netconf in cache.
Dump all attributes but no statistics.
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
struct rtnl_netconf * rtnl_netconf_get_all(struct nl_cache *cache, int family)
Search netconf in cache.
int nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf, size_t size)
Construct and transmit a Netlink message.
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
uint16_t type
Type of attribute or NLA_UNSPEC.
char * rtnl_link_i2name(struct nl_cache *cache, int ifindex, char *dst, size_t len)
Translate interface index to corresponding link name.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
struct rtnl_netconf * rtnl_netconf_get_default(struct nl_cache *cache, int family)
Search netconf in cache.
int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, struct nl_cache **result)
Allocate new cache and fill it.