8#include <linux/nexthop.h>
9#include <linux/lwtunnel.h>
10#include <linux/mpls_iptunnel.h>
12#include <netlink/route/nh.h>
13#include <netlink/hashtable.h>
14#include <netlink/route/nexthop.h>
16#include "nexthop-encap.h"
17#include "nl-aux-route/nl-route.h"
19#include "nl-priv-dynamic-core/nl-core.h"
20#include "nl-priv-dynamic-core/cache-api.h"
30 uint16_t nh_group_type;
31 nl_nh_group_t *nh_group;
33 struct nl_addr *nh_gateway;
34 struct rtnl_nh_encap *nh_encap;
37 uint16_t res_grp_buckets;
38 uint32_t res_grp_idle_timer;
39 uint32_t res_grp_unbalanced_timer;
42#define NH_ATTR_FLAGS (1 << 0)
43#define NH_ATTR_ID (1 << 1)
44#define NH_ATTR_GROUP (1 << 2)
45#define NH_ATTR_FLAG_BLACKHOLE (1 << 3)
46#define NH_ATTR_OIF (1 << 4)
47#define NH_ATTR_GATEWAY (1 << 5)
48#define NH_ATTR_FLAG_GROUPS (1 << 6)
49#define NH_ATTR_GROUP_TYPE (1 << 7)
50#define NH_ATTR_FLAG_FDB (1 << 8)
52#define NH_ATTR_RES_GROUP (1 << 9)
53#define NH_ATTR_RES_BUCKETS (1 << 10)
54#define NH_ATTR_RES_IDLE_TIMER (1 << 11)
55#define NH_ATTR_RES_UNBALANCED_TIMER (1 << 12)
56#define NH_ATTR_ENCAP (1 << 13)
59struct nla_policy rtnl_nh_policy[NHA_MAX + 1] = {
63 [NHA_GROUP_TYPE] = { .type =
NLA_U16 },
65 [NHA_OIF] = { .type =
NLA_U32 },
68 [NHA_ENCAP_TYPE] = { .type =
NLA_U16 },
71static struct nl_cache_ops rtnl_nh_ops;
72static struct nl_object_ops nh_obj_ops;
74static nl_nh_group_t *rtnl_nh_grp_alloc(
unsigned size)
78 _nl_assert(size <= (
unsigned)INT_MAX);
80 if (!(nhg = calloc(1,
sizeof(*nhg))))
85 if (!(nhg->entries = calloc(size,
sizeof(*nhg->entries)))) {
95static void rtnl_nh_grp_put(nl_nh_group_t *nhg)
100 _nl_assert(nhg->ce_refcnt > 0);
104 if (nhg->ce_refcnt > 0)
111static int rtnh_nh_grp_cmp(
const nl_nh_group_t *a,
const nl_nh_group_t *b)
116 _NL_CMP_DIRECT(a->size, b->size);
117 for (i = 0; i < a->size; i++) {
118 _NL_CMP_DIRECT(a->entries[i].
nh_id, b->entries[i].
nh_id);
119 _NL_CMP_DIRECT(a->entries[i].
weight, b->entries[i].
weight);
124static int rtnh_nh_grp_clone(nl_nh_group_t *src, nl_nh_group_t **dst)
129 ret = rtnl_nh_grp_alloc(src->size);
134 for (i = 0; i < src->size; i++) {
135 ret->entries[i].
nh_id = src->entries[i].
nh_id;
144struct rtnl_nh *rtnl_nh_alloc(
void)
149static int nh_clone(
struct nl_object *_src,
struct nl_object *_dst)
151 struct rtnl_nh *dst = nl_object_priv(_dst);
152 struct rtnl_nh *src = nl_object_priv(_src);
154 dst->nh_flags = src->nh_flags;
155 dst->nh_family = src->nh_family;
156 dst->nh_id = src->nh_id;
157 dst->nh_oif = src->nh_oif;
158 dst->nh_group_type = src->nh_group_type;
159 dst->res_grp_buckets = src->res_grp_buckets;
160 dst->res_grp_idle_timer = src->res_grp_idle_timer;
161 dst->res_grp_unbalanced_timer = src->res_grp_unbalanced_timer;
162 dst->ce_mask = src->ce_mask;
165 dst->nh_encap = rtnl_nh_encap_clone(src->nh_encap);
168 dst->ce_mask |= NH_ATTR_ENCAP;
171 if (src->nh_gateway) {
173 if (!dst->nh_gateway) {
179 if (rtnh_nh_grp_clone(src->nh_group, &dst->nh_group) < 0) {
187static void nh_free(
struct nl_object *obj)
189 struct rtnl_nh *nh = nl_object_priv(obj);
192 rtnl_nh_encap_free(nh->nh_encap);
193 rtnl_nh_grp_put(nh->nh_group);
196void rtnl_nh_put(
struct rtnl_nh *nh)
198 struct nl_object *obj = (
struct nl_object *)nh;
203static void nexthop_keygen(
struct nl_object *obj, uint32_t *hashkey,
206 struct rtnl_nh *nexthop = nl_object_priv(obj);
207 unsigned int lkey_sz;
208 struct nexthop_hash_key {
212 lkey_sz =
sizeof(lkey);
213 lkey.nh_id = nexthop->nh_id;
215 *hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
220int rtnl_nh_set_gateway(
struct rtnl_nh *nexthop,
struct nl_addr *addr)
222 struct nl_addr *old = NULL;
228 old = nexthop->nh_gateway;
235 nexthop->nh_gateway = cloned;
236 nexthop->ce_mask |= NH_ATTR_GATEWAY;
238 nexthop->nh_gateway = NULL;
239 nexthop->ce_mask &= ~NH_ATTR_GATEWAY;
248struct nl_addr *rtnl_nh_get_gateway(
struct rtnl_nh *nexthop)
250 return nexthop->nh_gateway;
266int rtnl_nh_set_encap(
struct rtnl_nh *nh,
struct rtnl_nh_encap *encap)
269 rtnl_nh_encap_free(encap);
273 if (encap && !encap->ops) {
274 rtnl_nh_encap_free(encap);
278 rtnl_nh_encap_free(nh->nh_encap);
281 nh->nh_encap = encap;
282 nh->ce_mask |= NH_ATTR_ENCAP;
285 nh->ce_mask &= ~NH_ATTR_ENCAP;
293 if (!nh || !(nh->ce_mask & NH_ATTR_ENCAP))
299int rtnl_nh_set_fdb(
struct rtnl_nh *nexthop,
int value)
302 nexthop->ce_mask |= NH_ATTR_FLAG_FDB;
304 nexthop->ce_mask &= ~NH_ATTR_FLAG_FDB;
309int rtnl_nh_get_oif(
struct rtnl_nh *nexthop)
311 if (nexthop->ce_mask & NH_ATTR_OIF)
312 return nexthop->nh_oif;
317int rtnl_nh_set_oif(
struct rtnl_nh *nexthop, uint32_t ifindex)
322 nexthop->nh_oif = (uint32_t)ifindex;
325 nexthop->ce_mask |= NH_ATTR_OIF;
327 nexthop->ce_mask &= ~NH_ATTR_OIF;
332int rtnl_nh_get_fdb(
struct rtnl_nh *nexthop)
334 return nexthop->ce_mask & NH_ATTR_FLAG_FDB;
337int rtnl_nh_set_family(
struct rtnl_nh *nexthop, uint8_t family)
342 nexthop->nh_family = family;
347int rtnl_nh_get_family(
struct rtnl_nh *nexthop)
352 return nexthop->nh_family;
355int rtnl_nh_set_group_type(
struct rtnl_nh *nexthop, uint16_t group_type)
360 nexthop->nh_group_type = group_type;
361 nexthop->ce_mask |= NH_ATTR_GROUP_TYPE;
366int rtnl_nh_get_group_type(
struct rtnl_nh *nexthop)
371 if (!(nexthop->ce_mask & NH_ATTR_GROUP_TYPE))
374 return (
int)nexthop->nh_group_type;
377static int _nh_resilient_check(
struct rtnl_nh *nexthop)
383 if (nexthop->nh_group_type != NEXTHOP_GRP_TYPE_RES)
389int rtnl_nh_set_res_group_bucket_size(
struct rtnl_nh *nexthop, uint16_t buckets)
391 int err = _nh_resilient_check(nexthop);
395 nexthop->res_grp_buckets = buckets;
398 nexthop->ce_mask |= NH_ATTR_RES_BUCKETS;
400 nexthop->ce_mask &= ~NH_ATTR_RES_BUCKETS;
406int rtnl_nh_get_res_group_bucket_size(
struct rtnl_nh *nexthop)
408 int err = _nh_resilient_check(nexthop);
412 if (!(nexthop->ce_mask & NH_ATTR_RES_BUCKETS))
413 return -NLE_MISSING_ATTR;
415 return nexthop->res_grp_buckets;
418int rtnl_nh_set_res_group_idle_timer(
struct rtnl_nh *nexthop,
421 int err = _nh_resilient_check(nexthop);
425 nexthop->res_grp_idle_timer = idle_timer;
426 nexthop->ce_mask |= NH_ATTR_RES_IDLE_TIMER;
431int rtnl_nh_get_res_group_idle_timer(
struct rtnl_nh *nexthop,
434 int err = _nh_resilient_check(nexthop);
441 if (!(nexthop->ce_mask & NH_ATTR_RES_IDLE_TIMER))
442 return -NLE_MISSING_ATTR;
444 *out_value = nexthop->res_grp_idle_timer;
449int rtnl_nh_set_res_group_unbalanced_timer(
struct rtnl_nh *nexthop,
450 uint32_t unbalanced_timer)
452 int err = _nh_resilient_check(nexthop);
456 nexthop->res_grp_unbalanced_timer = unbalanced_timer;
457 nexthop->ce_mask |= NH_ATTR_RES_UNBALANCED_TIMER;
462int rtnl_nh_get_res_group_unbalanced_timer(
struct rtnl_nh *nexthop,
465 int err = _nh_resilient_check(nexthop);
472 if (!(nexthop->ce_mask & NH_ATTR_RES_UNBALANCED_TIMER))
473 return -NLE_MISSING_ATTR;
475 *out_value = nexthop->res_grp_unbalanced_timer;
480int rtnl_nh_set_group(
struct rtnl_nh *nexthop,
481 const nl_nh_group_info_t *entries,
unsigned size)
483 nl_nh_group_t *nhg = NULL;
488 if (size > 0 && !entries)
494 rtnl_nh_grp_put(nexthop->nh_group);
495 nexthop->nh_group = NULL;
496 nexthop->ce_mask &= ~NH_ATTR_GROUP;
501 nhg = rtnl_nh_grp_alloc(size);
505 memcpy(nhg->entries, entries, size *
sizeof(*nhg->entries));
508 rtnl_nh_grp_put(nexthop->nh_group);
509 nexthop->nh_group = nhg;
510 nexthop->ce_mask |= NH_ATTR_GROUP;
515int rtnl_nh_get_group_entry(
struct rtnl_nh *nexthop,
int n)
517 if (!(nexthop->ce_mask & NH_ATTR_GROUP) || !nexthop->nh_group)
518 return -NLE_MISSING_ATTR;
520 if (n < 0 || ((
unsigned)n) >= nexthop->nh_group->size)
523 return nexthop->nh_group->entries[n].nh_id;
526int rtnl_nh_get_group_size(
struct rtnl_nh *nexthop)
528 if (!(nexthop->ce_mask & NH_ATTR_GROUP) || !nexthop->nh_group)
529 return -NLE_MISSING_ATTR;
531 _nl_assert(nexthop->nh_group->size <= INT_MAX);
533 return (
int)nexthop->nh_group->size;
536static int rtnl_nh_grp_info(
unsigned size,
const struct nexthop_grp *vi,
542 if (!(ret = rtnl_nh_grp_alloc(size)))
545 for (i = 0; i < size; i++) {
546 ret->entries[i].
nh_id = vi[i].id;
547 ret->entries[i].
weight = vi[i].weight;
554int rtnl_nh_get_id(
struct rtnl_nh *nh)
556 if (nh->ce_mask & NH_ATTR_ID)
562int rtnl_nh_set_id(
struct rtnl_nh *nh, uint32_t
id)
570 nh->ce_mask |= NH_ATTR_ID;
572 nh->ce_mask &= ~NH_ATTR_ID;
582static int rtnl_nh_build_msg(
struct nl_msg *msg,
struct rtnl_nh *nh)
585 .nh_family = nh->nh_family,
587 .nh_flags = nh->nh_flags,
590 if (
nlmsg_append(msg, &hdr,
sizeof(hdr), NLMSG_ALIGNTO) < 0)
594 if (nh->ce_mask & NH_ATTR_ID)
597 if (nh->ce_mask & NH_ATTR_OIF)
600 if (nh->ce_mask & NH_ATTR_GATEWAY) {
606 if (nh->ce_mask & NH_ATTR_FLAG_BLACKHOLE)
609 if (nh->ce_mask & NH_ATTR_ENCAP) {
610 struct nlattr *encap;
612 if (!nh->nh_encap || !nh->nh_encap->ops)
615 NLA_PUT_U16(msg, NHA_ENCAP_TYPE, nh->nh_encap->ops->encap_type);
619 goto nla_put_failure;
621 if (nh->nh_encap->ops->build_msg) {
622 int err = nh->nh_encap->ops->build_msg(
623 msg, nh->nh_encap->priv);
631 if (nh->ce_mask & NH_ATTR_GROUP) {
632 struct nexthop_grp *grp;
636 if (!nh->nh_group || nh->nh_group->size == 0)
639 sz = nh->nh_group->size *
sizeof(
struct nexthop_grp);
642 goto nla_put_failure;
645 for (
unsigned int i = 0; i < nh->nh_group->size; i++) {
646 grp[i].id = nh->nh_group->entries[i].nh_id;
647 grp[i].weight = nh->nh_group->entries[i].weight;
653 if (nh->nh_group_type)
654 NLA_PUT_U16(msg, NHA_GROUP_TYPE, nh->nh_group_type);
661 if (nh->nh_group_type == NEXTHOP_GRP_TYPE_RES &&
663 (NH_ATTR_RES_BUCKETS | NH_ATTR_RES_IDLE_TIMER |
664 NH_ATTR_RES_UNBALANCED_TIMER))) {
665 struct nlattr *res_grp;
669 goto nla_put_failure;
671 if (nh->ce_mask & NH_ATTR_RES_BUCKETS)
673 nh->res_grp_buckets);
675 if (nh->ce_mask & NH_ATTR_RES_IDLE_TIMER)
677 nh->res_grp_idle_timer);
679 if (nh->ce_mask & NH_ATTR_RES_UNBALANCED_TIMER)
681 nh->res_grp_unbalanced_timer);
694static int build_nh_msg(
struct rtnl_nh *tmpl,
int cmd,
int flags,
695 struct nl_msg **result)
697 _nl_auto_nl_msg
struct nl_msg *msg = NULL;
704 err = rtnl_nh_build_msg(msg, tmpl);
709 *result = _nl_steal_pointer(&msg);
713static int rtnl_nh_build_add_request(
struct rtnl_nh *tmpl,
int flags,
714 struct nl_msg **result)
716 return build_nh_msg(tmpl, RTM_NEWNEXTHOP, NLM_F_CREATE | flags, result);
719int rtnl_nh_add(
struct nl_sock *sk,
struct rtnl_nh *nh,
int flags)
721 _nl_auto_nl_msg
struct nl_msg *msg = NULL;
724 err = rtnl_nh_build_add_request(nh, flags, &msg);
732 return wait_for_ack(sk);
747 return nh_encap->ops->encap_type;
755 if (nh_encap->ops && nh_encap->ops->destructor)
756 nh_encap->ops->destructor(nh_encap->priv);
758 free(nh_encap->priv);
764 _nl_auto_rtnl_nh_encap
struct rtnl_nh_encap *new_encap = NULL;
769 new_encap = rtnl_nh_encap_alloc();
773 new_encap->ops = src->ops;
774 if (new_encap->ops) {
775 new_encap->priv = new_encap->ops->clone(src->priv);
776 if (!new_encap->priv)
780 return _nl_steal_pointer(&new_encap);
786struct rtnl_nh_encap *rtnl_route_nh_get_encap(
struct rtnl_nexthop *nh)
791 return nh->rtnh_encap;
794static struct nla_policy nh_res_group_policy[NHA_RES_GROUP_MAX + 1] = {
795 [NHA_RES_GROUP_UNSPEC] = { .type =
NLA_UNSPEC },
796 [NHA_RES_GROUP_BUCKETS] = { .type =
NLA_U16 },
797 [NHA_RES_GROUP_IDLE_TIMER] = { .type =
NLA_U32 },
798 [NHA_RES_GROUP_UNBALANCED_TIMER] = { .type =
NLA_U32 },
799 [NHA_RES_GROUP_UNBALANCED_TIME] = { .type =
NLA_U64 },
802static int nexthop_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
803 struct nlmsghdr *n,
struct nl_parser_param *pp)
805 _nl_auto_rtnl_nh
struct rtnl_nh *nexthop = NULL;
807 struct nlattr *tb[NHA_MAX + 1];
811 nexthop = rtnl_nh_alloc();
815 nexthop->ce_msgtype = n->nlmsg_type;
817 if (!nlmsg_valid_hdr(n,
sizeof(*ifi)))
818 return -NLE_MSG_TOOSHORT;
821 family = ifi->nh_family;
822 nexthop->nh_family = family;
823 nexthop->nh_flags = ifi->nh_flags;
824 nexthop->ce_mask = (NH_ATTR_FLAGS);
826 err =
nlmsg_parse(n,
sizeof(*ifi), tb, NHA_MAX, rtnl_nh_policy);
832 nexthop->ce_mask |= NH_ATTR_ID;
837 nexthop->ce_mask |= NH_ATTR_OIF;
840 if (tb[NHA_GATEWAY]) {
841 nexthop->nh_gateway =
843 nexthop->ce_mask |= NH_ATTR_GATEWAY;
846 if (tb[NHA_GROUP_TYPE]) {
847 nexthop->nh_group_type =
nla_get_u16(tb[NHA_GROUP_TYPE]);
848 nexthop->ce_mask |= NH_ATTR_GROUP_TYPE;
851 if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) {
852 _nl_auto_rtnl_nh_encap
struct rtnl_nh_encap *nh_encap = NULL;
854 err = nh_encap_parse_msg(tb[NHA_ENCAP], tb[NHA_ENCAP_TYPE],
859 err = rtnl_nh_set_encap(nexthop, _nl_steal_pointer(&nh_encap));
864 if (tb[NHA_BLACKHOLE]) {
865 nexthop->ce_mask |= NH_ATTR_FLAG_BLACKHOLE;
868 if (tb[NHA_GROUPS]) {
869 nexthop->ce_mask |= NH_ATTR_FLAG_GROUPS;
873 nexthop->ce_mask |= NH_ATTR_FLAG_FDB;
877 nl_nh_group_t *nh_group = NULL;
883 len = _nla_len(tb[NHA_GROUP]);
884 size = len /
sizeof(
struct nexthop_grp);
886 err = rtnl_nh_grp_info(size, (
const struct nexthop_grp *)data,
892 nexthop->nh_group = nh_group;
893 nexthop->ce_mask |= NH_ATTR_GROUP;
897 if (tb[NHA_RES_GROUP]) {
898 struct nlattr *rg[NHA_RES_GROUP_MAX + 1];
901 nh_res_group_policy);
905 if (rg[NHA_RES_GROUP_BUCKETS]) {
906 nexthop->res_grp_buckets =
908 nexthop->ce_mask |= NH_ATTR_RES_BUCKETS;
910 if (rg[NHA_RES_GROUP_IDLE_TIMER]) {
911 nexthop->res_grp_idle_timer =
913 nexthop->ce_mask |= NH_ATTR_RES_IDLE_TIMER;
915 if (rg[NHA_RES_GROUP_UNBALANCED_TIMER]) {
916 nexthop->res_grp_unbalanced_timer =
918 nexthop->ce_mask |= NH_ATTR_RES_UNBALANCED_TIMER;
921 nexthop->ce_mask |= NH_ATTR_RES_GROUP;
924 return pp->pp_cb((
struct nl_object *)nexthop, pp);
927static int nexthop_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
929 _nl_auto_nl_msg
struct nl_msg *msg = NULL;
930 int family = cache->c_iarg1;
931 struct nhmsg hdr = { .nh_family = family };
938 if (
nlmsg_append(msg, &hdr,
sizeof(hdr), NLMSG_ALIGNTO) < 0)
948static void dump_nh_group(nl_nh_group_t *group,
struct nl_dump_params *dp)
953 for (i = 0; i < group->size; i++) {
958static void nh_dump_line(
struct nl_object *obj,
struct nl_dump_params *dp)
960 struct nl_cache *cache;
962 struct rtnl_nh *nh = nl_object_priv(obj);
966 if (nh->ce_mask & NH_ATTR_ID)
967 nl_dump(dp,
"nhid %u", nh->nh_id);
969 if (nh->ce_mask & NH_ATTR_OIF)
970 nl_dump(dp,
" oif %d", nh->nh_oif);
972 if (nh->ce_mask & NH_ATTR_GATEWAY)
976 if (nh->ce_mask & NH_ATTR_ENCAP && nh->nh_encap)
977 nh_encap_dump(nh->nh_encap, dp);
979 if (nh->ce_mask & NH_ATTR_FLAG_BLACKHOLE)
982 if (nh->ce_mask & NH_ATTR_FLAG_GROUPS)
985 if (nh->ce_mask & NH_ATTR_GROUP)
986 dump_nh_group(nh->nh_group, dp);
989 if (nh->nh_group_type == NEXTHOP_GRP_TYPE_RES) {
990 if (nh->ce_mask & NH_ATTR_RES_BUCKETS)
991 nl_dump(dp,
" buckets %u", nh->res_grp_buckets);
992 if (nh->ce_mask & NH_ATTR_RES_IDLE_TIMER)
993 nl_dump(dp,
" idle-timer %u", nh->res_grp_idle_timer);
994 if (nh->ce_mask & NH_ATTR_RES_UNBALANCED_TIMER)
995 nl_dump(dp,
" unbalanced-timer %u",
996 nh->res_grp_unbalanced_timer);
999 if (nh->ce_mask & NH_ATTR_FLAG_FDB)
1005 nl_cache_put(cache);
1008static void nh_dump_details(
struct nl_object *nh,
struct nl_dump_params *dp)
1010 nh_dump_line(nh, dp);
1013static uint64_t nh_compare(
struct nl_object *a,
struct nl_object *b,
1014 uint64_t attrs,
int loose)
1017 struct rtnl_nh *src = nl_object_priv(a);
1018 struct rtnl_nh *dst = nl_object_priv(b);
1020#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
1021 diff |= _DIFF(NH_ATTR_ID, src->nh_id != dst->nh_id);
1022 diff |= _DIFF(NH_ATTR_GATEWAY,
1024 diff |= _DIFF(NH_ATTR_OIF, src->nh_oif != dst->nh_oif);
1025 diff |= _DIFF(NH_ATTR_GROUP,
1026 rtnh_nh_grp_cmp(src->nh_group, dst->nh_group));
1027 diff |= _DIFF(NH_ATTR_GROUP_TYPE,
1028 src->nh_group_type != dst->nh_group_type);
1029 diff |= _DIFF(NH_ATTR_FLAG_FDB,
false);
1030 diff |= _DIFF(NH_ATTR_FLAG_GROUPS,
false);
1031 diff |= _DIFF(NH_ATTR_FLAG_BLACKHOLE,
false);
1032 diff |= _DIFF(NH_ATTR_RES_BUCKETS,
1033 src->res_grp_buckets != dst->res_grp_buckets);
1034 diff |= _DIFF(NH_ATTR_RES_IDLE_TIMER,
1035 src->res_grp_idle_timer != dst->res_grp_idle_timer);
1036 diff |= _DIFF(NH_ATTR_RES_UNBALANCED_TIMER,
1037 src->res_grp_unbalanced_timer !=
1038 dst->res_grp_unbalanced_timer);
1039 diff |= _DIFF(NH_ATTR_ENCAP,
1040 nh_encap_compare(src->nh_encap, dst->nh_encap));
1046struct rtnl_nh *rtnl_nh_get(
struct nl_cache *cache,
int nhid)
1050 if (cache->c_ops != &rtnl_nh_ops)
1053 nl_list_for_each_entry(nh, &cache->c_items, ce_list) {
1054 if (nh->nh_id == ((
unsigned)nhid)) {
1088static int rtnl_nh_alloc_cache_flags(
struct nl_sock *sk,
int family,
1089 struct nl_cache **result,
1092 struct nl_cache *cache;
1099 cache->c_iarg1 = family;
1137int rtnl_nh_alloc_cache(
struct nl_sock *sk,
int family,
1138 struct nl_cache **result)
1140 return rtnl_nh_alloc_cache_flags(sk, family, result, 0);
1143static struct nl_object_ops nh_obj_ops = {
1144 .oo_name =
"route/nh",
1145 .oo_size =
sizeof(
struct rtnl_nh),
1146 .oo_free_data = nh_free,
1147 .oo_clone = nh_clone,
1152 .oo_compare = nh_compare,
1153 .oo_keygen = nexthop_keygen,
1154 .oo_attrs2str = rtnl_route_nh_flags2str,
1155 .oo_id_attrs = NH_ATTR_ID,
1158static struct nl_af_group nh_groups[] = {
1159 { AF_UNSPEC, RTNLGRP_NEXTHOP },
1160 { END_OF_GROUP_LIST },
1163static struct nl_cache_ops rtnl_nh_ops = {
1164 .co_name =
"route/nh",
1165 .co_hdrsize =
sizeof(
struct nhmsg),
1167 { RTM_NEWNEXTHOP, NL_ACT_NEW,
"new" },
1168 { RTM_DELNEXTHOP, NL_ACT_DEL,
"del" },
1169 { RTM_GETNEXTHOP, NL_ACT_GET,
"get" },
1170 END_OF_MSGTYPES_LIST,
1172 .co_protocol = NETLINK_ROUTE,
1173 .co_groups = nh_groups,
1174 .co_request_update = nexthop_request_update,
1175 .co_msg_parser = nexthop_msg_parser,
1176 .co_obj_ops = &nh_obj_ops,
1179static void _nl_init nexthop_init(
void)
1184static 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.
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
#define NLA_PUT_FLAG(msg, attrtype)
Add flag attribute to netlink message.
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
#define NLA_PUT_ADDR(msg, attrtype, addr)
Add address attribute to netlink message.
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
struct nlattr * nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
Reserve space for a attribute.
@ 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.
int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
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.