Skip to content

Commit 6d4859c

Browse files
committed
[nexthop] Add rtnl_nh_add
This allows to push the nexthop to the kernel. Similar to `ip nexthop add` command. Signed-off-by: Christoph Paasch <[email protected]>
1 parent f638f5c commit 6d4859c

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-0
lines changed

include/netlink/route/nh.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ typedef struct nl_nh_group {
2929
extern int rtnl_nh_alloc_cache(struct nl_sock *sk, int family,
3030
struct nl_cache **result);
3131
extern struct rtnl_nh *rtnl_nh_alloc(void);
32+
extern int rtnl_nh_add(struct nl_sock *sk, struct rtnl_nh *nh, int flags);
3233
extern void rtnl_nh_put(struct rtnl_nh *);
3334

3435
extern struct rtnl_nh *rtnl_nh_get(struct nl_cache *cache, int nhid);

lib/route/nh.c

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,143 @@ int rtnl_nh_set_id(struct rtnl_nh *nh, uint32_t id)
514514
return 0;
515515
}
516516

517+
/* ------------------------------------------------------------------------- */
518+
/* Message construction & kernel interaction */
519+
/* ------------------------------------------------------------------------- */
520+
521+
/* Build a netlink message representing the supplied nexthop object. */
522+
static int rtnl_nh_build_msg(struct nl_msg *msg, struct rtnl_nh *nh)
523+
{
524+
struct nhmsg hdr = {
525+
.nh_family = nh->nh_family,
526+
.nh_protocol = 0, /* kernel will fill in */
527+
.nh_flags = nh->nh_flags,
528+
};
529+
530+
if (nlmsg_append(msg, &hdr, sizeof(hdr), NLMSG_ALIGNTO) < 0)
531+
return -NLE_MSGSIZE;
532+
533+
/* Optional attributes */
534+
if (nh->ce_mask & NH_ATTR_ID)
535+
NLA_PUT_U32(msg, NHA_ID, nh->nh_id);
536+
537+
if (nh->ce_mask & NH_ATTR_OIF)
538+
NLA_PUT_U32(msg, NHA_OIF, nh->nh_oif);
539+
540+
if (nh->ce_mask & NH_ATTR_GATEWAY) {
541+
if (!nh->nh_gateway)
542+
return -NLE_INVAL;
543+
NLA_PUT_ADDR(msg, NHA_GATEWAY, nh->nh_gateway);
544+
}
545+
546+
if (nh->ce_mask & NH_ATTR_FLAG_BLACKHOLE)
547+
NLA_PUT_FLAG(msg, NHA_BLACKHOLE);
548+
549+
/* Nexthop group */
550+
if (nh->ce_mask & NH_ATTR_GROUP) {
551+
struct nexthop_grp *grp;
552+
struct nlattr *attr;
553+
unsigned int sz;
554+
555+
if (!nh->nh_group || nh->nh_group->size == 0)
556+
return -NLE_INVAL;
557+
558+
sz = nh->nh_group->size * sizeof(struct nexthop_grp);
559+
attr = nla_reserve(msg, NHA_GROUP, sz);
560+
if (!attr)
561+
goto nla_put_failure;
562+
563+
grp = nla_data(attr);
564+
for (unsigned int i = 0; i < nh->nh_group->size; i++) {
565+
grp[i].id = nh->nh_group->entries[i].nh_id;
566+
grp[i].weight = nh->nh_group->entries[i].weight;
567+
grp[i].resvd1 = 0;
568+
grp[i].resvd2 = 0;
569+
}
570+
571+
/* Optional group type */
572+
if (nh->nh_group_type)
573+
NLA_PUT_U16(msg, NHA_GROUP_TYPE, nh->nh_group_type);
574+
575+
/* If the group type is resilient and the caller supplied additional
576+
* resilient parameters (bucket size, timers, ...), add them as a
577+
* nested NHA_RES_GROUP attribute. Only pass through the parameters
578+
* that were explicitly set on the nexthop object.
579+
*/
580+
if (nh->nh_group_type == NEXTHOP_GRP_TYPE_RES &&
581+
(nh->ce_mask &
582+
(NH_ATTR_RES_BUCKETS | NH_ATTR_RES_IDLE_TIMER |
583+
NH_ATTR_RES_UNBALANCED_TIMER))) {
584+
struct nlattr *res_grp;
585+
586+
res_grp = nla_nest_start(msg, NHA_RES_GROUP);
587+
if (!res_grp)
588+
goto nla_put_failure;
589+
590+
if (nh->ce_mask & NH_ATTR_RES_BUCKETS)
591+
NLA_PUT_U16(msg, NHA_RES_GROUP_BUCKETS,
592+
nh->res_grp_buckets);
593+
594+
if (nh->ce_mask & NH_ATTR_RES_IDLE_TIMER)
595+
NLA_PUT_U32(msg, NHA_RES_GROUP_IDLE_TIMER,
596+
nh->res_grp_idle_timer);
597+
598+
if (nh->ce_mask & NH_ATTR_RES_UNBALANCED_TIMER)
599+
NLA_PUT_U32(msg, NHA_RES_GROUP_UNBALANCED_TIMER,
600+
nh->res_grp_unbalanced_timer);
601+
602+
nla_nest_end(msg, res_grp);
603+
}
604+
}
605+
606+
return 0;
607+
608+
nla_put_failure:
609+
return -NLE_MSGSIZE;
610+
}
611+
612+
/* Helper to build generic nexthop request messages */
613+
static int build_nh_msg(struct rtnl_nh *tmpl, int cmd, int flags,
614+
struct nl_msg **result)
615+
{
616+
_nl_auto_nl_msg struct nl_msg *msg = NULL;
617+
int err;
618+
619+
msg = nlmsg_alloc_simple(cmd, flags);
620+
if (!msg)
621+
return -NLE_NOMEM;
622+
623+
err = rtnl_nh_build_msg(msg, tmpl);
624+
if (err < 0) {
625+
return err;
626+
}
627+
628+
*result = _nl_steal_pointer(&msg);
629+
return 0;
630+
}
631+
632+
static int rtnl_nh_build_add_request(struct rtnl_nh *tmpl, int flags,
633+
struct nl_msg **result)
634+
{
635+
return build_nh_msg(tmpl, RTM_NEWNEXTHOP, NLM_F_CREATE | flags, result);
636+
}
637+
638+
int rtnl_nh_add(struct nl_sock *sk, struct rtnl_nh *nh, int flags)
639+
{
640+
_nl_auto_nl_msg struct nl_msg *msg = NULL;
641+
int err;
642+
643+
err = rtnl_nh_build_add_request(nh, flags, &msg);
644+
if (err < 0)
645+
return err;
646+
647+
err = nl_send_auto_complete(sk, msg);
648+
if (err < 0)
649+
return err;
650+
651+
return wait_for_ack(sk);
652+
}
653+
517654
static struct nla_policy nh_res_group_policy[NHA_RES_GROUP_MAX + 1] = {
518655
[NHA_RES_GROUP_UNSPEC] = { .type = NLA_UNSPEC },
519656
[NHA_RES_GROUP_BUCKETS] = { .type = NLA_U16 },

libnl-route-3.sym

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,7 @@ global:
13701370
rtnl_link_ip6_tnl_get_collect_metadata;
13711371
rtnl_link_ip6_tnl_set_collect_metadata;
13721372
rtnl_link_is_bond;
1373+
rtnl_nh_add;
13731374
rtnl_nh_get_family;
13741375
rtnl_nh_get_group_type;
13751376
rtnl_nh_get_oif;

0 commit comments

Comments
 (0)