Skip to content

Commit 933edc3

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 f4d68e9 commit 933edc3

File tree

3 files changed

+141
-0
lines changed

3 files changed

+141
-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: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,145 @@ int rtnl_nh_set_id(struct rtnl_nh *nh, uint32_t id)
516516
return 0;
517517
}
518518

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