[PATCH libnl 1/4] route: Add support for netconf
David Ahern
dsa at cumulusnetworks.com
Thu Apr 27 13:42:33 PDT 2017
Add route/netconf cache type to monitor RTM_*NETCONF messages.
Signed-off-by: David Ahern <dsa at cumulusnetworks.com>
Signed-off-by: Balakrishnan Raman <ramanb at cumulusnetworks.com>
---
Makefile.am | 2 +
include/linux-private/linux/netconf.h | 27 ++
include/linux-private/linux/rtnetlink.h | 2 +
include/netlink/route/netconf.h | 43 +++
lib/route/netconf.c | 501 ++++++++++++++++++++++++++++++++
libnl-route-3.sym | 9 +
6 files changed, 584 insertions(+)
create mode 100644 include/linux-private/linux/netconf.h
create mode 100644 include/netlink/route/netconf.h
create mode 100644 lib/route/netconf.c
diff --git a/Makefile.am b/Makefile.am
index 1b95a559304f..aaf44c8a4731 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 000000000000..ec14058e9b33
--- /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 32449478c72d..7d94908c04ae 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 000000000000..6c9ec3cc935e
--- /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 at 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 rtnl_netconf_get_ifindex(struct rtnl_netconf *nc);
+int rtnl_netconf_get_forwarding(struct rtnl_netconf *nc);
+int rtnl_netconf_get_mc_forwarding(struct rtnl_netconf *nc);
+int rtnl_netconf_get_rp_filter(struct rtnl_netconf *nc);
+int rtnl_netconf_get_proxy_neigh(struct rtnl_netconf *nc);
+int rtnl_netconf_get_ignore_routes_linkdown(struct rtnl_netconf *nc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/route/netconf.c b/lib/route/netconf.c
new file mode 100644
index 000000000000..6569d8bf01f4
--- /dev/null
+++ b/lib/route/netconf.c
@@ -0,0 +1,501 @@
+/*
+ * 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 at 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)
+{
+ return nc->family;
+}
+int rtnl_netconf_get_ifindex(struct rtnl_netconf *nc)
+{
+ return nc->ifindex;
+}
+int rtnl_netconf_get_forwarding(struct rtnl_netconf *nc)
+{
+ return nc->ce_mask & NETCONF_ATTR_FWDING ? nc->forwarding : -1;
+}
+int rtnl_netconf_get_mc_forwarding(struct rtnl_netconf *nc)
+{
+ return nc->ce_mask & NETCONF_ATTR_MC_FWDING ? nc->mc_forwarding : -1;
+}
+int rtnl_netconf_get_rp_filter(struct rtnl_netconf *nc)
+{
+ return nc->ce_mask & NETCONF_ATTR_RP_FILTER ? nc->rp_filter : -1;
+}
+int rtnl_netconf_get_proxy_neigh(struct rtnl_netconf *nc)
+{
+ return nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH ? nc->proxy_neigh : -1;
+}
+int rtnl_netconf_get_ignore_routes_linkdown(struct rtnl_netconf *nc)
+{
+ if (nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN)
+ return nc->ignore_routes_linkdown;
+
+ return -1;
+}
+
+/** @} */
+
+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 af1ed2dd561d..00abcaf5dbf2 100644
--- a/libnl-route-3.sym
+++ b/libnl-route-3.sym
@@ -1030,5 +1030,14 @@ libnl_3_2_29 {
rtnl_link_vf_str2vlanproto;
rtnl_link_vf_str2guid;
rtnl_u32_set_selector;
+ 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_28;
--
2.1.4
More information about the libnl
mailing list