diff options
author | David Ahern <dsahern@gmail.com> | 2017-05-03 21:05:06 (GMT) |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-05-12 08:09:15 (GMT) |
commit | d55f004c5ad4b202cab5593551554cdad4f1a444 (patch) | |
tree | 2b32b2e5137b445e065a9f787bc15569d8e12f54 | |
parent | b5513d46aa7917676cdc9cf2cc7c9e376d6c36b1 (diff) | |
download | libnl-d55f004c5ad4b202cab5593551554cdad4f1a444.zip libnl-d55f004c5ad4b202cab5593551554cdad4f1a444.tar.gz libnl-d55f004c5ad4b202cab5593551554cdad4f1a444.tar.bz2 |
route: Add support for netconf
Add route/netconf cache type to monitor RTM_*NETCONF messages.
v2
- change get methods to return 0/error and take 'int *val'
which is set to the value requested
Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: Balakrishnan Raman <ramanb@cumulusnetworks.com>
Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | include/linux-private/linux/netconf.h | 27 | ||||
-rw-r--r-- | include/linux-private/linux/rtnetlink.h | 2 | ||||
-rw-r--r-- | include/netlink/route/netconf.h | 43 | ||||
-rw-r--r-- | lib/route/netconf.c | 540 | ||||
-rw-r--r-- | libnl-route-3.sym | 9 |
6 files changed, 623 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am index 1b95a55..aaf44c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -100,6 +100,7 @@ libnlinclude_netlink_route_HEADERS = \ include/netlink/route/link.h \ include/netlink/route/neighbour.h \ include/netlink/route/neightbl.h \ + include/netlink/route/netconf.h \ include/netlink/route/nexthop.h \ include/netlink/route/pktloc.h \ include/netlink/route/qdisc.h \ @@ -380,6 +381,7 @@ lib_libnl_route_3_la_SOURCES = \ lib/route/link/vxlan.c \ lib/route/neigh.c \ lib/route/neightbl.c \ + lib/route/netconf.c \ lib/route/nexthop.c \ lib/route/pktloc.c \ lib/route/qdisc/blackhole.c \ diff --git a/include/linux-private/linux/netconf.h b/include/linux-private/linux/netconf.h new file mode 100644 index 0000000..ec14058 --- /dev/null +++ b/include/linux-private/linux/netconf.h @@ -0,0 +1,27 @@ +#ifndef __LINUX_NETCONF_H_ +#define __LINUX_NETCONF_H_ + +#include <linux/types.h> +#include <linux/netlink.h> + +struct netconfmsg { + __u8 ncm_family; +}; + +enum { + NETCONFA_UNSPEC, + NETCONFA_IFINDEX, + NETCONFA_FORWARDING, + NETCONFA_RP_FILTER, + NETCONFA_MC_FORWARDING, + NETCONFA_PROXY_NEIGH, + NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, + __NETCONFA_MAX +}; +#define NETCONFA_MAX (__NETCONFA_MAX - 1) +#define NETCONFA_ALL -1 + +#define NETCONFA_IFINDEX_ALL -1 +#define NETCONFA_IFINDEX_DEFAULT -2 + +#endif /* __LINUX_NETCONF_H_ */ diff --git a/include/linux-private/linux/rtnetlink.h b/include/linux-private/linux/rtnetlink.h index 3244947..7d94908 100644 --- a/include/linux-private/linux/rtnetlink.h +++ b/include/linux-private/linux/rtnetlink.h @@ -122,6 +122,8 @@ enum { RTM_NEWNETCONF = 80, #define RTM_NEWNETCONF RTM_NEWNETCONF + RTM_DELNETCONF, +#define RTM_DELNETCONF RTM_DELNETCONF RTM_GETNETCONF = 82, #define RTM_GETNETCONF RTM_GETNETCONF diff --git a/include/netlink/route/netconf.h b/include/netlink/route/netconf.h new file mode 100644 index 0000000..d2d1f9b --- /dev/null +++ b/include/netlink/route/netconf.h @@ -0,0 +1,43 @@ +/* + * netlink/route/netconf.h rtnetlink netconf layer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2017 David Ahern <dsa@cumulusnetworks.com> + */ + +#ifndef NETCONF_H_ +#define NETCONF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct rtnl_netconf; + +int rtnl_netconf_alloc_cache(struct nl_sock *sk, struct nl_cache **result); + +struct rtnl_netconf *rtnl_netconf_get_by_idx(struct nl_cache *cache, int family, + int ifindex); +struct rtnl_netconf *rtnl_netconf_get_all(struct nl_cache *cache, + int family); +struct rtnl_netconf *rtnl_netconf_get_default(struct nl_cache *cache, + int family); +void rtnl_netconf_put(struct rtnl_netconf *nc); + +int rtnl_netconf_get_family(struct rtnl_netconf *nc, int *val); +int rtnl_netconf_get_ifindex(struct rtnl_netconf *nc, int *val); +int rtnl_netconf_get_forwarding(struct rtnl_netconf *nc, int *val); +int rtnl_netconf_get_mc_forwarding(struct rtnl_netconf *nc, int *val); +int rtnl_netconf_get_rp_filter(struct rtnl_netconf *nc, int *val); +int rtnl_netconf_get_proxy_neigh(struct rtnl_netconf *nc, int *val); +int rtnl_netconf_get_ignore_routes_linkdown(struct rtnl_netconf *nc, int *val); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/route/netconf.c b/lib/route/netconf.c new file mode 100644 index 0000000..2073c94 --- /dev/null +++ b/lib/route/netconf.c @@ -0,0 +1,540 @@ +/* + * lib/route/netconf.c netconf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2017 David Ahern <dsa@cumulusnetworks.com> + */ + +/** + * @ingroup rtnl + * @defgroup netconf Netconf + * @brief + * + * @{ + */ + +#include <netlink-private/netlink.h> +#include <netlink/netlink.h> +#include <netlink/utils.h> +#include <netlink/route/netconf.h> +#include <linux/netconf.h> +#include <netlink/hashtable.h> + +/** @cond SKIP */ +#define NETCONF_ATTR_FAMILY 0x0001 +#define NETCONF_ATTR_IFINDEX 0x0002 +#define NETCONF_ATTR_RP_FILTER 0x0004 +#define NETCONF_ATTR_FWDING 0x0008 +#define NETCONF_ATTR_MC_FWDING 0x0010 +#define NETCONF_ATTR_PROXY_NEIGH 0x0020 +#define NETCONF_ATTR_IGNORE_RT_LINKDWN 0x0040 + +struct rtnl_netconf +{ + NLHDR_COMMON + + int family; + int ifindex; + int rp_filter; + int forwarding; + int mc_forwarding; + int proxy_neigh; + int ignore_routes_linkdown; +}; + +static struct nl_cache_ops rtnl_netconf_ops; +static struct nl_object_ops netconf_obj_ops; +/** @endcond */ + +static struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = { + [NETCONFA_IFINDEX] = { .type = NLA_S32 }, + [NETCONFA_FORWARDING] = { .type = NLA_S32 }, + [NETCONFA_MC_FORWARDING] = { .type = NLA_S32 }, + [NETCONFA_RP_FILTER] = { .type = NLA_S32 }, + [NETCONFA_PROXY_NEIGH] = { .type = NLA_S32 }, + [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .type = NLA_S32 }, +}; + +static struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { + [NETCONFA_IFINDEX] = { .type = NLA_S32 }, + [NETCONFA_FORWARDING] = { .type = NLA_S32 }, + [NETCONFA_MC_FORWARDING] = { .type = NLA_S32 }, + [NETCONFA_PROXY_NEIGH] = { .type = NLA_S32 }, + [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .type = NLA_S32 }, +}; + +static struct rtnl_netconf *rtnl_netconf_alloc(void) +{ + return (struct rtnl_netconf *) nl_object_alloc(&netconf_obj_ops); +} + +static int netconf_clone(struct nl_object *_dst, struct nl_object *_src) +{ + struct rtnl_netconf *dst = nl_object_priv(_dst); + struct rtnl_netconf *src = nl_object_priv(_src); + + *dst = *src; + + return 0; +} + +static int netconf_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct nlattr *tb[NETCONFA_MAX+1], *attr; + struct rtnl_netconf *nc; + struct netconfmsg *ncm; + int err; + + ncm = nlmsg_data(nlh); + switch (ncm->ncm_family) { + case AF_INET: + err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, + devconf_ipv4_policy); + if (err < 0) + return err; + break; + case AF_INET6: + err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, + devconf_ipv6_policy); + if (err < 0) + return err; + break; + default: + printf("unexpected netconf family: %d\n", ncm->ncm_family); + return -1; + } + + if (!tb[NETCONFA_IFINDEX]) + return -1; + + nc = rtnl_netconf_alloc(); + if (!nc) + return -NLE_NOMEM; + + nc->ce_msgtype = nlh->nlmsg_type; + nc->family = ncm->ncm_family; + nc->ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); + + nc->ce_mask = NETCONF_ATTR_FAMILY | NETCONF_ATTR_IFINDEX; + + + if (tb[NETCONFA_RP_FILTER]) { + attr = tb[NETCONFA_RP_FILTER]; + nc->rp_filter = nla_get_s32(attr); + nc->ce_mask |= NETCONF_ATTR_RP_FILTER; + } + + if (tb[NETCONFA_FORWARDING]) { + attr = tb[NETCONFA_FORWARDING]; + nc->forwarding = nla_get_s32(attr); + nc->ce_mask |= NETCONF_ATTR_FWDING; + } + + if (tb[NETCONFA_MC_FORWARDING]) { + attr = tb[NETCONFA_MC_FORWARDING]; + nc->mc_forwarding = nla_get_s32(attr); + nc->ce_mask |= NETCONF_ATTR_MC_FWDING; + } + + if (tb[NETCONFA_PROXY_NEIGH]) { + attr = tb[NETCONFA_PROXY_NEIGH]; + nc->proxy_neigh = nla_get_s32(attr); + nc->ce_mask |= NETCONF_ATTR_PROXY_NEIGH; + } + + if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) { + attr = tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]; + nc->ignore_routes_linkdown = nla_get_s32(attr); + nc->ce_mask |= NETCONF_ATTR_IGNORE_RT_LINKDWN; + } + + return pp->pp_cb((struct nl_object *) nc, pp); +} + +static int netconf_request_update(struct nl_cache *cache, struct nl_sock *sk) +{ + struct netconfmsg nc = { + .ncm_family = cache->c_iarg1, + }; + + return nl_send_simple(sk, RTM_GETNETCONF, NLM_F_DUMP, &nc, sizeof(nc)); +} + +static void netconf_dump_line(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_netconf *nc = (struct rtnl_netconf *) obj; + struct nl_cache *link_cache; + char buf[64]; + + switch(nc->family) { + case AF_INET: + nl_dump(p, "ipv4 "); + break; + case AF_INET6: + nl_dump(p, "ipv6 "); + break; + default: + return; + } + + switch(nc->ifindex) { + case NETCONFA_IFINDEX_ALL: + nl_dump(p, "all "); + break; + case NETCONFA_IFINDEX_DEFAULT: + nl_dump(p, "default "); + break; + default: + link_cache = nl_cache_mngt_require_safe("route/link"); + if (link_cache) { + nl_dump(p, "dev %s ", + rtnl_link_i2name(link_cache, nc->ifindex, + buf, sizeof(buf))); + nl_cache_put(link_cache); + } else + nl_dump(p, "dev %d ", nc->ifindex); + } + + if (nc->ce_mask & NETCONF_ATTR_FWDING) { + nl_dump(p, "forwarding %s ", + nc->forwarding ? "on" : "off"); + } + + if (nc->ce_mask & NETCONF_ATTR_RP_FILTER) { + if (nc->rp_filter == 0) + nl_dump(p, "rp_filter off "); + else if (nc->rp_filter == 1) + nl_dump(p, "rp_filter strict "); + else if (nc->rp_filter == 2) + nl_dump(p, "rp_filter loose "); + else + nl_dump(p, "rp_filter unknown-mode "); + } + + if (nc->ce_mask & NETCONF_ATTR_MC_FWDING) { + nl_dump(p, "mc_forwarding %s ", + nc->mc_forwarding ? "on" : "off"); + } + + if (nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH) + nl_dump(p, "proxy_neigh %d ", nc->proxy_neigh); + + if (nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN) { + nl_dump(p, "ignore_routes_with_linkdown %s ", + nc->ignore_routes_linkdown ? "on" : "off"); + } + + nl_dump(p, "\n"); +} + +static const struct trans_tbl netconf_attrs[] = { + __ADD(NETCONF_ATTR_FAMILY, family), + __ADD(NETCONF_ATTR_IFINDEX, ifindex), + __ADD(NETCONF_ATTR_RP_FILTER, rp_filter), + __ADD(NETCONF_ATTR_FWDING, forwarding), + __ADD(NETCONF_ATTR_MC_FWDING, mc_forwarding), + __ADD(NETCONF_ATTR_PROXY_NEIGH, proxy_neigh), + __ADD(NETCONF_ATTR_IGNORE_RT_LINKDWN, ignore_routes_with_linkdown), +}; + +static char *netconf_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, netconf_attrs, + ARRAY_SIZE(netconf_attrs)); +} + +static void netconf_keygen(struct nl_object *obj, uint32_t *hashkey, + uint32_t table_sz) +{ + struct rtnl_netconf *nc = (struct rtnl_netconf *) obj; + unsigned int nckey_sz; + struct nc_hash_key { + int nc_family; + int nc_index; + } __attribute__((packed)) nckey; + + nckey_sz = sizeof(nckey); + nckey.nc_family = nc->family; + nckey.nc_index = nc->ifindex; + + *hashkey = nl_hash(&nckey, nckey_sz, 0) % table_sz; + + NL_DBG(5, "netconf %p key (dev %d fam %d) keysz %d, hash 0x%x\n", + nc, nckey.nc_index, nckey.nc_family, nckey_sz, *hashkey); +} + +static uint64_t netconf_compare(struct nl_object *_a, struct nl_object *_b, + uint64_t attrs, int flags) +{ + struct rtnl_netconf *a = (struct rtnl_netconf *) _a; + struct rtnl_netconf *b = (struct rtnl_netconf *) _b; + uint64_t diff = 0; + +#define NETCONF_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NETCONF_ATTR_##ATTR, a, b, EXPR) + + diff |= NETCONF_DIFF(FAMILY, a->family != b->family); + diff |= NETCONF_DIFF(IFINDEX, a->ifindex != b->ifindex); + diff |= NETCONF_DIFF(RP_FILTER, a->rp_filter != b->rp_filter); + diff |= NETCONF_DIFF(FWDING, a->forwarding != b->forwarding); + diff |= NETCONF_DIFF(MC_FWDING, a->mc_forwarding != b->mc_forwarding); + diff |= NETCONF_DIFF(PROXY_NEIGH, a->proxy_neigh != b->proxy_neigh); + diff |= NETCONF_DIFF(IGNORE_RT_LINKDWN, + a->ignore_routes_linkdown != b->ignore_routes_linkdown); + +#undef NETCONF_DIFF + + return diff; +} + +static int netconf_update(struct nl_object *old_obj, struct nl_object *new_obj) +{ + struct rtnl_netconf *new_nc = (struct rtnl_netconf *) new_obj; + struct rtnl_netconf *old_nc = (struct rtnl_netconf *) old_obj; + int action = new_obj->ce_msgtype; + + switch(action) { + case RTM_NEWNETCONF: + if (new_nc->family != old_nc->family || + new_nc->ifindex != old_nc->ifindex) + return -NLE_OPNOTSUPP; + + if (new_nc->ce_mask & NETCONF_ATTR_RP_FILTER) + old_nc->rp_filter = new_nc->rp_filter; + if (new_nc->ce_mask & NETCONF_ATTR_FWDING) + old_nc->forwarding = new_nc->forwarding; + if (new_nc->ce_mask & NETCONF_ATTR_MC_FWDING) + old_nc->mc_forwarding = new_nc->mc_forwarding; + if (new_nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH) + old_nc->proxy_neigh = new_nc->proxy_neigh; + if (new_nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN) + old_nc->ignore_routes_linkdown = new_nc->ignore_routes_linkdown; + + break; + default: + return -NLE_OPNOTSUPP; + } + + return NLE_SUCCESS; +} + +/** + * @name Cache Management + * @{ + */ + +int rtnl_netconf_alloc_cache(struct nl_sock *sk, struct nl_cache **result) +{ + return nl_cache_alloc_and_fill(&rtnl_netconf_ops, sk, result); +} + +/** + * Search netconf in cache + * @arg cache netconf cache + * @arg family Address family of interest + * @arg ifindex Interface index of interest + * + * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache() + * for given index and family + * + * The reference counter is incremented before returning the netconf entry, + * therefore the reference must be given back with rtnl_netconf_put() after + * usage. + * + * @return netconf object or NULL if no match was found. + */ +struct rtnl_netconf *rtnl_netconf_get_by_idx(struct nl_cache *cache, int family, + int ifindex) +{ + struct rtnl_netconf *nc; + + if (!ifindex || !family || cache->c_ops != &rtnl_netconf_ops) + return NULL; + + nl_list_for_each_entry(nc, &cache->c_items, ce_list) { + if (nc->ifindex == ifindex && + nc->family == family) { + nl_object_get((struct nl_object *) nc); + return nc; + } + } + + return NULL; +} + +void rtnl_netconf_put(struct rtnl_netconf *nc) +{ + nl_object_put((struct nl_object *) nc); +} + +/** + * Search netconf in cache + * @arg cache netconf cache + * @arg family Address family of interest + * + * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache() + * for "all" netconf settings for given family + * + * The reference counter is incremented before returning the netconf entry, + * therefore the reference must be given back with rtnl_netconf_put() after + * usage. + * + * @return netconf object or NULL if no match was found. + */ +struct rtnl_netconf *rtnl_netconf_get_all(struct nl_cache *cache, int family) +{ + return rtnl_netconf_get_by_idx(cache, family, NETCONFA_IFINDEX_ALL); +} + +/** + * Search netconf in cache + * @arg cache netconf cache + * @arg family Address family of interest + * + * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache() + * for "default" netconf settings for given family + * + * The reference counter is incremented before returning the netconf entry, + * therefore the reference must be given back with rtnl_netconf_put() after + * usage. + * + * @return netconf object or NULL if no match was found. + */ +struct rtnl_netconf *rtnl_netconf_get_default(struct nl_cache *cache, int family) +{ + return rtnl_netconf_get_by_idx(cache, family, NETCONFA_IFINDEX_DEFAULT); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +int rtnl_netconf_get_family(struct rtnl_netconf *nc, int *val) +{ + if (!nc) + return -NLE_INVAL; + if (!(nc->ce_mask & NETCONF_ATTR_FAMILY)) + return -NLE_MISSING_ATTR; + if (val) + *val = nc->family; + return 0; +} +int rtnl_netconf_get_ifindex(struct rtnl_netconf *nc, int *val) +{ + if (!nc) + return -NLE_INVAL; + if (!(nc->ce_mask & NETCONF_ATTR_IFINDEX)) + return -NLE_MISSING_ATTR; + if (val) + *val = nc->ifindex; + return 0; +} +int rtnl_netconf_get_forwarding(struct rtnl_netconf *nc, int *val) +{ + if (!nc) + return -NLE_INVAL; + if (!(nc->ce_mask & NETCONF_ATTR_FWDING)) + return -NLE_MISSING_ATTR; + if (val) + *val = nc->forwarding; + return 0; +} +int rtnl_netconf_get_mc_forwarding(struct rtnl_netconf *nc, int *val) +{ + if (!nc) + return -NLE_INVAL; + if (!(nc->ce_mask & NETCONF_ATTR_MC_FWDING)) + return -NLE_MISSING_ATTR; + if (val) + *val = nc->mc_forwarding; + return 0; +} +int rtnl_netconf_get_rp_filter(struct rtnl_netconf *nc, int *val) +{ + if (!nc) + return -NLE_INVAL; + if (!(nc->ce_mask & NETCONF_ATTR_RP_FILTER)) + return -NLE_MISSING_ATTR; + if (val) + *val = nc->rp_filter; + return 0; +} +int rtnl_netconf_get_proxy_neigh(struct rtnl_netconf *nc, int *val) +{ + if (!nc) + return -NLE_INVAL; + if (!(nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH)) + return -NLE_MISSING_ATTR; + if (val) + *val = nc->proxy_neigh; + return 0; +} +int rtnl_netconf_get_ignore_routes_linkdown(struct rtnl_netconf *nc, int *val) +{ + if (!nc) + return -NLE_INVAL; + if (!(nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN)) + return -NLE_MISSING_ATTR; + if (val) + *val = nc->ignore_routes_linkdown; + return 0; +} + +/** @} */ + +static struct nl_object_ops netconf_obj_ops = { + .oo_name = "route/netconf", + .oo_size = sizeof(struct rtnl_netconf), + .oo_clone = netconf_clone, + .oo_dump = { + [NL_DUMP_LINE] = netconf_dump_line, + [NL_DUMP_DETAILS] = netconf_dump_line, + }, + .oo_compare = netconf_compare, + .oo_keygen = netconf_keygen, + .oo_update = netconf_update, + .oo_attrs2str = netconf_attrs2str, + .oo_id_attrs = (NETCONF_ATTR_FAMILY | + NETCONF_ATTR_IFINDEX) +}; + +static struct nl_af_group netconf_groups[] = { + { AF_INET, RTNLGRP_IPV4_NETCONF }, + { AF_INET6, RTNLGRP_IPV6_NETCONF }, + { END_OF_GROUP_LIST }, +}; + +static struct nl_cache_ops rtnl_netconf_ops = { + .co_name = "route/netconf", + .co_hdrsize = sizeof(struct netconfmsg), + .co_msgtypes = { + { RTM_NEWNETCONF, NL_ACT_NEW, "new" }, + { RTM_DELNETCONF, NL_ACT_DEL, "del" }, + { RTM_GETNETCONF, NL_ACT_GET, "get" }, + END_OF_MSGTYPES_LIST, + }, + .co_protocol = NETLINK_ROUTE, + .co_groups = netconf_groups, + .co_request_update = netconf_request_update, + .co_msg_parser = netconf_msg_parser, + .co_obj_ops = &netconf_obj_ops, +}; + +static void __init netconf_init(void) +{ + nl_cache_mngt_register(&rtnl_netconf_ops); +} + +static void __exit netconf_exit(void) +{ + nl_cache_mngt_unregister(&rtnl_netconf_ops); +} + +/** @} */ diff --git a/libnl-route-3.sym b/libnl-route-3.sym index 1fb4371..b17434c 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -1041,4 +1041,13 @@ global: rtnl_link_inet6_get_flags; rtnl_link_inet6_set_flags; rtnl_u32_get_action; + rtnl_netconf_get_by_idx; + rtnl_netconf_get_all; + rtnl_netconf_get_default; + rtnl_netconf_put; + rtnl_netconf_get_family; + rtnl_netconf_get_ifindex; + rtnl_netconf_get_forwarding; + rtnl_netconf_get_mc_forwarding; + rtnl_netconf_get_rp_filter; } libnl_3_2_29; |