8#include <linux/nexthop.h>
10#include <netlink/route/nh.h>
11#include <netlink/hashtable.h>
12#include <netlink/route/nexthop.h>
14#include "nl-aux-route/nl-route.h"
16#include "nl-priv-dynamic-core/nl-core.h"
17#include "nl-priv-dynamic-core/cache-api.h"
27 uint32_t nh_group_type;
30 struct nl_addr *nh_gateway;
33#define NH_ATTR_FLAGS (1 << 0)
34#define NH_ATTR_ID (1 << 1)
35#define NH_ATTR_GROUP (1 << 2)
36#define NH_ATTR_FLAG_BLACKHOLE (1 << 3)
37#define NH_ATTR_OIF (1 << 4)
38#define NH_ATTR_GATEWAY (1 << 5)
39#define NH_ATTR_FLAG_GROUPS (1 << 6)
40#define NH_ATTR_FLAG_FDB (1 << 8)
52static struct nl_cache_ops rtnl_nh_ops;
53static struct nl_object_ops nh_obj_ops;
59 _nl_assert(size <= (
unsigned)INT_MAX);
61 if (!(nhg = calloc(1,
sizeof(*nhg))))
66 if (!(nhg->entries = calloc(size,
sizeof(*nhg->entries)))) {
81 _nl_assert(nhg->ce_refcnt > 0);
85 if (nhg->ce_refcnt > 0)
96 _NL_CMP_DIRECT(a->size, b->size);
97 for (i = 0; i < a->size; i++) {
98 _NL_CMP_DIRECT(a->entries[i].
nh_id, b->entries[i].
nh_id);
99 _NL_CMP_DIRECT(a->entries[i].
weight, b->entries[i].
weight);
109 ret = rtnl_nh_grp_alloc(src->size);
114 for (i = 0; i < src->size; i++) {
115 ret->entries[i].
nh_id = src->entries[i].
nh_id;
124struct rtnl_nh *rtnl_nh_alloc(
void)
129static int nh_clone(
struct nl_object *_src,
struct nl_object *_dst)
131 struct rtnl_nh *dst = nl_object_priv(_dst);
132 struct rtnl_nh *src = nl_object_priv(_src);
134 dst->nh_flags = src->nh_flags;
135 dst->nh_family = src->nh_family;
136 dst->nh_id = src->nh_id;
137 dst->nh_oif = src->nh_oif;
138 dst->ce_mask = src->ce_mask;
140 if (src->nh_gateway) {
142 if (!dst->nh_gateway) {
148 if (rtnh_nh_grp_clone(src->nh_group, &dst->nh_group) < 0) {
156static void nh_free(
struct nl_object *obj)
158 struct rtnl_nh *nh = nl_object_priv(obj);
162 rtnl_nh_grp_put(nh->nh_group);
165void rtnl_nh_put(
struct rtnl_nh *nh)
167 struct nl_object *obj = (
struct nl_object *)nh;
172static void nexthop_keygen(
struct nl_object *obj, uint32_t *hashkey,
175 struct rtnl_nh *nexthop = nl_object_priv(obj);
176 unsigned int lkey_sz;
177 struct nexthop_hash_key {
181 lkey_sz =
sizeof(lkey);
182 lkey.nh_id = nexthop->nh_id;
184 *hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
189int rtnl_nh_set_gateway(
struct rtnl_nh *nexthop,
struct nl_addr *addr)
191 if (nexthop->ce_mask & NH_ATTR_GATEWAY) {
196 nexthop->ce_mask |= NH_ATTR_GATEWAY;
201struct nl_addr *rtnl_nh_get_gateway(
struct rtnl_nh *nexthop)
203 return nexthop->nh_gateway;
206int rtnl_nh_set_fdb(
struct rtnl_nh *nexthop,
int value)
209 nexthop->ce_mask |= NH_ATTR_FLAG_FDB;
211 nexthop->ce_mask &= ~NH_ATTR_FLAG_FDB;
216int rtnl_nh_get_oif(
struct rtnl_nh *nexthop)
218 if (nexthop->ce_mask & NH_ATTR_OIF)
219 return nexthop->nh_oif;
224int rtnl_nh_get_fdb(
struct rtnl_nh *nexthop)
226 return nexthop->ce_mask & NH_ATTR_FLAG_FDB;
229int rtnl_nh_get_group_entry(
struct rtnl_nh *nexthop,
int n)
231 if (!(nexthop->ce_mask & NH_ATTR_GROUP) || !nexthop->nh_group)
232 return -NLE_MISSING_ATTR;
234 if (n < 0 || ((
unsigned)n) >= nexthop->nh_group->size)
237 return nexthop->nh_group->entries[n].nh_id;
240int rtnl_nh_get_group_size(
struct rtnl_nh *nexthop)
242 if (!(nexthop->ce_mask & NH_ATTR_GROUP) || !nexthop->nh_group)
243 return -NLE_MISSING_ATTR;
245 _nl_assert(nexthop->nh_group->size <= INT_MAX);
247 return (
int)nexthop->nh_group->size;
250static int rtnl_nh_grp_info(
unsigned size,
const struct nexthop_grp *vi,
256 if (!(ret = rtnl_nh_grp_alloc(size)))
259 for (i = 0; i < size; i++) {
260 ret->entries[i].
nh_id = vi[i].id;
261 ret->entries[i].
weight = vi[i].weight;
268int rtnl_nh_get_id(
struct rtnl_nh *nh)
270 if (nh->ce_mask & NH_ATTR_ID)
276static int nexthop_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
277 struct nlmsghdr *n,
struct nl_parser_param *pp)
279 _nl_auto_rtnl_nh
struct rtnl_nh *nexthop = NULL;
281 struct nlattr *tb[NHA_MAX + 1];
285 nexthop = rtnl_nh_alloc();
289 nexthop->ce_msgtype = n->nlmsg_type;
291 if (!nlmsg_valid_hdr(n,
sizeof(*ifi)))
292 return -NLE_MSG_TOOSHORT;
295 family = ifi->nh_family;
296 nexthop->nh_family = family;
297 nexthop->nh_flags = ifi->nh_flags;
298 nexthop->ce_mask = (NH_ATTR_FLAGS);
300 err =
nlmsg_parse(n,
sizeof(*ifi), tb, NHA_MAX, rtnl_nh_policy);
306 nexthop->ce_mask |= NH_ATTR_ID;
311 nexthop->ce_mask |= NH_ATTR_OIF;
314 if (tb[NHA_GATEWAY]) {
315 nexthop->nh_gateway =
317 nexthop->ce_mask |= NH_ATTR_GATEWAY;
320 if (tb[NHA_BLACKHOLE]) {
321 nexthop->ce_mask |= NH_ATTR_FLAG_BLACKHOLE;
324 if (tb[NHA_GROUPS]) {
325 nexthop->ce_mask |= NH_ATTR_FLAG_GROUPS;
329 nexthop->ce_mask |= NH_ATTR_FLAG_FDB;
339 len = _nla_len(tb[NHA_GROUP]);
340 size = len /
sizeof(
struct nexthop_grp);
342 err = rtnl_nh_grp_info(size, (
const struct nexthop_grp *)data,
348 nexthop->nh_group = nh_group;
349 nexthop->ce_mask |= NH_ATTR_GROUP;
352 return pp->pp_cb((
struct nl_object *)nexthop, pp);
355static int nexthop_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
357 _nl_auto_nl_msg
struct nl_msg *msg = NULL;
358 int family = cache->c_iarg1;
359 struct nhmsg hdr = { .nh_family = family };
366 if (
nlmsg_append(msg, &hdr,
sizeof(hdr), NLMSG_ALIGNTO) < 0)
381 for (i = 0; i < group->size; i++) {
386static void nh_dump_line(
struct nl_object *obj,
struct nl_dump_params *dp)
388 struct nl_cache *cache;
390 struct rtnl_nh *nh = nl_object_priv(obj);
394 if (nh->ce_mask & NH_ATTR_ID)
395 nl_dump(dp,
"nhid %u", nh->nh_id);
397 if (nh->ce_mask & NH_ATTR_OIF)
398 nl_dump(dp,
" oif %d", nh->nh_oif);
400 if (nh->ce_mask & NH_ATTR_GATEWAY)
404 if (nh->ce_mask & NH_ATTR_FLAG_BLACKHOLE)
407 if (nh->ce_mask & NH_ATTR_FLAG_GROUPS)
410 if (nh->ce_mask & NH_ATTR_GROUP)
411 dump_nh_group(nh->nh_group, dp);
413 if (nh->ce_mask & NH_ATTR_FLAG_FDB)
422static void nh_dump_details(
struct nl_object *nh,
struct nl_dump_params *dp)
424 nh_dump_line(nh, dp);
427static uint64_t nh_compare(
struct nl_object *a,
struct nl_object *b,
428 uint64_t attrs,
int loose)
431 struct rtnl_nh *src = nl_object_priv(a);
432 struct rtnl_nh *dst = nl_object_priv(b);
434#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
435 diff |= _DIFF(NH_ATTR_ID, src->nh_id != dst->nh_id);
436 diff |= _DIFF(NH_ATTR_GATEWAY,
438 diff |= _DIFF(NH_ATTR_OIF, src->nh_oif != dst->nh_oif);
439 diff |= _DIFF(NH_ATTR_GROUP,
440 rtnh_nh_grp_cmp(src->nh_group, dst->nh_group));
441 diff |= _DIFF(NH_ATTR_FLAG_FDB,
false);
442 diff |= _DIFF(NH_ATTR_FLAG_GROUPS,
false);
443 diff |= _DIFF(NH_ATTR_FLAG_BLACKHOLE,
false);
449struct rtnl_nh *rtnl_nh_get(
struct nl_cache *cache,
int nhid)
453 if (cache->c_ops != &rtnl_nh_ops)
456 nl_list_for_each_entry(nh, &cache->c_items, ce_list) {
457 if (nh->nh_id == ((
unsigned)nhid)) {
491static int rtnl_nh_alloc_cache_flags(
struct nl_sock *sk,
int family,
492 struct nl_cache **result,
495 struct nl_cache *cache;
502 cache->c_iarg1 = family;
540int rtnl_nh_alloc_cache(
struct nl_sock *sk,
int family,
541 struct nl_cache **result)
543 return rtnl_nh_alloc_cache_flags(sk, family, result, 0);
546static struct nl_object_ops nh_obj_ops = {
547 .oo_name =
"route/nh",
548 .oo_size =
sizeof(
struct rtnl_nh),
549 .oo_free_data = nh_free,
550 .oo_clone = nh_clone,
555 .oo_compare = nh_compare,
556 .oo_keygen = nexthop_keygen,
557 .oo_attrs2str = rtnl_route_nh_flags2str,
558 .oo_id_attrs = NH_ATTR_ID,
561static struct nl_af_group nh_groups[] = {
562 { AF_UNSPEC, RTNLGRP_NEXTHOP },
563 { END_OF_GROUP_LIST },
566static struct nl_cache_ops rtnl_nh_ops = {
567 .co_name =
"route/nh",
568 .co_hdrsize =
sizeof(
struct nhmsg),
570 { RTM_NEWNEXTHOP, NL_ACT_NEW,
"new" },
571 { RTM_DELNEXTHOP, NL_ACT_DEL,
"del" },
572 { RTM_GETNEXTHOP, NL_ACT_GET,
"get" },
573 END_OF_MSGTYPES_LIST,
575 .co_protocol = NETLINK_ROUTE,
576 .co_groups = nh_groups,
577 .co_request_update = nexthop_request_update,
578 .co_msg_parser = nexthop_msg_parser,
579 .co_obj_ops = &nh_obj_ops,
582static void _nl_init nexthop_init(
void)
587static void _nl_exit nexthop_exit(
void)
struct nl_addr * nl_addr_alloc_attr(const struct nlattr *nla, int family)
Allocate abstract address based on Netlink attribute.
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
@ NLA_UNSPEC
Unspecified type, binary data chunk.
@ NLA_NESTED
Nested attributes.
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
struct nl_cache * nl_cache_mngt_require_safe(const char *name)
Return cache previously provided via nl_cache_mngt_provide()
int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
(Re)fill a cache with the contents in the kernel.
void nl_cache_set_flags(struct nl_cache *cache, unsigned int flags)
Set cache flags.
void nl_cache_free(struct nl_cache *cache)
Free a cache.
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate new cache.
struct nl_msg * nlmsg_alloc_simple(int nlmsgtype, int flags)
Allocate a new netlink message.
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
Finalize and transmit Netlink message.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Attribute validation policy.
uint16_t type
Type of attribute or NLA_UNSPEC.