Skip to content

Commit 6ec1802

Browse files
committed
nh-encap: Allow adding a nh_encap to a rtnl_nh
A regular "nexthop object" à la `ip nexthop` can have an associated encapsulation. So, add the code to support that. Signed-off-by: Christoph Paasch <[email protected]>
1 parent 9b69403 commit 6ec1802

File tree

5 files changed

+246
-9
lines changed

5 files changed

+246
-9
lines changed

include/netlink/route/nh.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ extern int rtnl_nh_set_res_group_unbalanced_timer(struct rtnl_nh *,
7272
extern int rtnl_nh_get_res_group_unbalanced_timer(struct rtnl_nh *,
7373
uint32_t *out_value);
7474

75+
/* lwtunnel encapsulation */
76+
struct rtnl_nh_encap;
77+
extern int rtnl_nh_set_encap(struct rtnl_nh *, struct rtnl_nh_encap *);
78+
extern struct rtnl_nh_encap *rtnl_nh_get_encap(struct rtnl_nh *);
79+
7580
#ifdef __cplusplus
7681
}
7782
#endif

lib/route/nexthop_encap.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,23 +78,34 @@ int nh_encap_parse_msg(struct nlattr *encap, struct nlattr *encap_type,
7878

7979
if (e_type == LWTUNNEL_ENCAP_NONE) {
8080
NL_DBG(2, "RTA_ENCAP_TYPE should not be LWTUNNEL_ENCAP_NONE\n");
81-
return -NLE_INVAL;
81+
82+
goto unsupported_encap;
8283
}
84+
8385
if (e_type > LWTUNNEL_ENCAP_MAX) {
8486
NL_DBG(2, "Unknown RTA_ENCAP_TYPE: %d\n", e_type);
85-
return -NLE_INVAL;
87+
88+
goto unsupported_encap;
8689
}
8790

8891
if (!lwtunnel_encap_types[e_type].ops) {
8992
NL_DBG(2, "RTA_ENCAP_TYPE %s is not implemented\n",
9093
lwtunnel_encap_types[e_type].name);
91-
return -NLE_MSGTYPE_NOSUPPORT;
92-
}
9394

94-
if (!lwtunnel_encap_types[e_type].ops->parse_msg)
95-
return -NLE_MSGTYPE_NOSUPPORT;
95+
goto unsupported_encap;
96+
}
9697

9798
return lwtunnel_encap_types[e_type].ops->parse_msg(encap, encap_out);
99+
100+
unsupported_encap:
101+
/* If we don't yet support this lwtunnel, just return 0.
102+
*
103+
* Force encap_out to NULL so that subsequent calls to set
104+
* it on a nexthop/route will simply reset the encapsulation
105+
* on that nexthop/route.
106+
*/
107+
*encap_out = NULL;
108+
return 0;
98109
}
99110

100111
int nh_encap_compare(struct rtnl_nh_encap *a, struct rtnl_nh_encap *b)

lib/route/nh.c

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include "nl-default.h"
77

88
#include <linux/nexthop.h>
9+
#include <linux/lwtunnel.h>
10+
#include <linux/mpls_iptunnel.h>
911

1012
#include <netlink/route/nh.h>
1113
#include <netlink/hashtable.h>
@@ -29,6 +31,7 @@ struct rtnl_nh {
2931
nl_nh_group_t *nh_group;
3032
uint32_t nh_oif;
3133
struct nl_addr *nh_gateway;
34+
struct rtnl_nh_encap *nh_encap;
3235

3336
/* Resilient nexthop group parameters */
3437
uint16_t res_grp_buckets;
@@ -50,6 +53,7 @@ struct rtnl_nh {
5053
#define NH_ATTR_RES_BUCKETS (1 << 10)
5154
#define NH_ATTR_RES_IDLE_TIMER (1 << 11)
5255
#define NH_ATTR_RES_UNBALANCED_TIMER (1 << 12)
56+
#define NH_ATTR_ENCAP (1 << 13)
5357
/** @endcond */
5458

5559
struct nla_policy rtnl_nh_policy[NHA_MAX + 1] = {
@@ -60,6 +64,8 @@ struct nla_policy rtnl_nh_policy[NHA_MAX + 1] = {
6064
[NHA_BLACKHOLE] = { .type = NLA_UNSPEC },
6165
[NHA_OIF] = { .type = NLA_U32 },
6266
[NHA_RES_GROUP] = { .type = NLA_NESTED },
67+
[NHA_ENCAP] = { .type = NLA_NESTED },
68+
[NHA_ENCAP_TYPE] = { .type = NLA_U16 },
6369
};
6470

6571
static struct nl_cache_ops rtnl_nh_ops;
@@ -155,6 +161,13 @@ static int nh_clone(struct nl_object *_src, struct nl_object *_dst)
155161
dst->res_grp_unbalanced_timer = src->res_grp_unbalanced_timer;
156162
dst->ce_mask = src->ce_mask;
157163

164+
if (src->nh_encap) {
165+
dst->nh_encap = rtnl_nh_encap_clone(src->nh_encap);
166+
if (!dst->nh_encap)
167+
return -NLE_NOMEM;
168+
dst->ce_mask |= NH_ATTR_ENCAP;
169+
}
170+
158171
if (src->nh_gateway) {
159172
dst->nh_gateway = nl_addr_clone(src->nh_gateway);
160173
if (!dst->nh_gateway) {
@@ -174,10 +187,10 @@ static int nh_clone(struct nl_object *_src, struct nl_object *_dst)
174187
static void nh_free(struct nl_object *obj)
175188
{
176189
struct rtnl_nh *nh = nl_object_priv(obj);
177-
nl_addr_put(nh->nh_gateway);
178190

179-
if (nh->nh_group)
180-
rtnl_nh_grp_put(nh->nh_group);
191+
nl_addr_put(nh->nh_gateway);
192+
rtnl_nh_encap_free(nh->nh_encap);
193+
rtnl_nh_grp_put(nh->nh_group);
181194
}
182195

183196
void rtnl_nh_put(struct rtnl_nh *nh)
@@ -237,6 +250,52 @@ struct nl_addr *rtnl_nh_get_gateway(struct rtnl_nh *nexthop)
237250
return nexthop->nh_gateway;
238251
}
239252

253+
/**
254+
* Set nexthop encapsulation
255+
* @arg nh Nexthop object
256+
* @arg encap Encapsulation descriptor
257+
*
258+
* Assigns ownership of the encapsulation object to the nexthop. Any
259+
* previously configured encapsulation is released. Passing a NULL
260+
* encapsulation clears the encapsulation on the nexthop.
261+
*
262+
* On failure, the function consumes and frees encap.
263+
*
264+
* @return 0 on success, or the appropriate error-code on failure.
265+
*/
266+
int rtnl_nh_set_encap(struct rtnl_nh *nh, struct rtnl_nh_encap *encap)
267+
{
268+
if (!nh) {
269+
rtnl_nh_encap_free(encap);
270+
return -NLE_INVAL;
271+
}
272+
273+
if (encap && !encap->ops) {
274+
rtnl_nh_encap_free(encap);
275+
return -NLE_INVAL;
276+
}
277+
278+
rtnl_nh_encap_free(nh->nh_encap);
279+
280+
if (encap) {
281+
nh->nh_encap = encap;
282+
nh->ce_mask |= NH_ATTR_ENCAP;
283+
} else {
284+
nh->nh_encap = NULL;
285+
nh->ce_mask &= ~NH_ATTR_ENCAP;
286+
}
287+
288+
return 0;
289+
}
290+
291+
struct rtnl_nh_encap *rtnl_nh_get_encap(struct rtnl_nh *nh)
292+
{
293+
if (!nh || !(nh->ce_mask & NH_ATTR_ENCAP))
294+
return NULL;
295+
296+
return nh->nh_encap;
297+
}
298+
240299
int rtnl_nh_set_fdb(struct rtnl_nh *nexthop, int value)
241300
{
242301
if (value)
@@ -547,6 +606,27 @@ static int rtnl_nh_build_msg(struct nl_msg *msg, struct rtnl_nh *nh)
547606
if (nh->ce_mask & NH_ATTR_FLAG_BLACKHOLE)
548607
NLA_PUT_FLAG(msg, NHA_BLACKHOLE);
549608

609+
if (nh->ce_mask & NH_ATTR_ENCAP) {
610+
struct nlattr *encap;
611+
612+
if (!nh->nh_encap || !nh->nh_encap->ops)
613+
return -NLE_INVAL;
614+
615+
NLA_PUT_U16(msg, NHA_ENCAP_TYPE, nh->nh_encap->ops->encap_type);
616+
617+
encap = nla_nest_start(msg, NHA_ENCAP);
618+
if (!encap)
619+
goto nla_put_failure;
620+
621+
if (nh->nh_encap->ops->build_msg) {
622+
int err = nh->nh_encap->ops->build_msg(
623+
msg, nh->nh_encap->priv);
624+
if (err < 0)
625+
return err;
626+
}
627+
nla_nest_end(msg, encap);
628+
}
629+
550630
/* Nexthop group */
551631
if (nh->ce_mask & NH_ATTR_GROUP) {
552632
struct nexthop_grp *grp;
@@ -758,6 +838,19 @@ static int nexthop_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
758838
nexthop->ce_mask |= NH_ATTR_GROUP_TYPE;
759839
}
760840

841+
if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) {
842+
_nl_auto_rtnl_nh_encap struct rtnl_nh_encap *nh_encap = NULL;
843+
844+
err = nh_encap_parse_msg(tb[NHA_ENCAP], tb[NHA_ENCAP_TYPE],
845+
&nh_encap);
846+
if (err < 0)
847+
return err;
848+
849+
err = rtnl_nh_set_encap(nexthop, _nl_steal_pointer(&nh_encap));
850+
if (err < 0)
851+
return err;
852+
}
853+
761854
if (tb[NHA_BLACKHOLE]) {
762855
nexthop->ce_mask |= NH_ATTR_FLAG_BLACKHOLE;
763856
}
@@ -870,6 +963,9 @@ static void nh_dump_line(struct nl_object *obj, struct nl_dump_params *dp)
870963
nl_dump(dp, " via %s",
871964
nl_addr2str(nh->nh_gateway, buf, sizeof(buf)));
872965

966+
if (nh->ce_mask & NH_ATTR_ENCAP && nh->nh_encap)
967+
nh_encap_dump(nh->nh_encap, dp);
968+
873969
if (nh->ce_mask & NH_ATTR_FLAG_BLACKHOLE)
874970
nl_dump(dp, " blackhole");
875971

@@ -930,6 +1026,8 @@ static uint64_t nh_compare(struct nl_object *a, struct nl_object *b,
9301026
diff |= _DIFF(NH_ATTR_RES_UNBALANCED_TIMER,
9311027
src->res_grp_unbalanced_timer !=
9321028
dst->res_grp_unbalanced_timer);
1029+
diff |= _DIFF(NH_ATTR_ENCAP,
1030+
nh_encap_compare(src->nh_encap, dst->nh_encap));
9331031
#undef _DIFF
9341032

9351033
return diff;

libnl-route-3.sym

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,7 @@ global:
13751375
rtnl_nh_encap_clone;
13761376
rtnl_nh_encap_free;
13771377
rtnl_nh_encap_mpls;
1378+
rtnl_nh_get_encap;
13781379
rtnl_nh_get_encap_mpls_dst;
13791380
rtnl_nh_get_encap_mpls_ttl;
13801381
rtnl_nh_get_family;
@@ -1383,6 +1384,7 @@ global:
13831384
rtnl_nh_get_res_group_bucket_size;
13841385
rtnl_nh_get_res_group_idle_timer;
13851386
rtnl_nh_get_res_group_unbalanced_timer;
1387+
rtnl_nh_set_encap;
13861388
rtnl_nh_set_family;
13871389
rtnl_nh_set_group;
13881390
rtnl_nh_set_group_type;

0 commit comments

Comments
 (0)