Skip to content

Commit 1e68463

Browse files
committed
nh-encap: Support cloning rtnl_nh_encap in rtnl_route_nh_clone
Signed-off-by: Christoph Paasch <[email protected]>
1 parent fe179fb commit 1e68463

File tree

7 files changed

+74
-0
lines changed

7 files changed

+74
-0
lines changed

include/netlink/route/nexthop.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ extern int rtnl_route_nh_str2flags(const char *);
6262
*/
6363
extern struct rtnl_nh_encap *rtnl_nh_encap_alloc(void);
6464
extern void rtnl_nh_encap_free(struct rtnl_nh_encap *nh_encap);
65+
extern struct rtnl_nh_encap *rtnl_nh_encap_clone(struct rtnl_nh_encap *src);
6566

6667
extern int rtnl_nh_encap_mpls(struct rtnl_nh_encap *nh_encap,
6768
struct nl_addr *dst, uint8_t ttl);

lib/route/nexthop-encap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ struct nh_encap_ops {
88
int (*parse_msg)(struct nlattr *nla, struct rtnl_nexthop *rtnh);
99

1010
int (*compare)(void *a, void *b);
11+
void *(*clone)(void *priv);
1112

1213
void (*dump)(void *priv, struct nl_dump_params *dp);
1314
void (*destructor)(void *priv);

lib/route/nexthop.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
8383
return NULL;
8484
}
8585

86+
/* Clone encapsulation information if present */
87+
if (src->rtnh_encap) {
88+
nh->rtnh_encap = rtnl_nh_encap_clone(src->rtnh_encap);
89+
if (!nh->rtnh_encap)
90+
return NULL;
91+
}
92+
8693
return _nl_steal_pointer(&nh);
8794
}
8895

lib/route/nh.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,27 @@ void rtnl_nh_encap_free(struct rtnl_nh_encap *nh_encap)
669669
free(nh_encap);
670670
}
671671

672+
struct rtnl_nh_encap *rtnl_nh_encap_clone(struct rtnl_nh_encap *src)
673+
{
674+
_nl_auto_rtnl_nh_encap struct rtnl_nh_encap *new_encap = NULL;
675+
676+
if (!src)
677+
return NULL;
678+
679+
new_encap = rtnl_nh_encap_alloc();
680+
if (!new_encap)
681+
return NULL;
682+
683+
new_encap->ops = src->ops;
684+
if (new_encap->ops) {
685+
new_encap->priv = new_encap->ops->clone(src->priv);
686+
if (!new_encap->priv)
687+
return NULL;
688+
}
689+
690+
return _nl_steal_pointer(&new_encap);
691+
}
692+
672693
/*
673694
* Retrieve the encapsulation associated with a nexthop if any.
674695
*/

lib/route/nh_encap_mpls.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,24 @@ static void mpls_encap_destructor(void *priv)
4949
nl_addr_put(encap_info->dst);
5050
}
5151

52+
static void *mpls_encap_clone(void *priv)
53+
{
54+
struct mpls_iptunnel_encap *src = priv;
55+
struct mpls_iptunnel_encap *clone;
56+
57+
if (!src)
58+
return NULL;
59+
60+
clone = calloc(1, sizeof(*clone));
61+
if (!clone)
62+
return NULL;
63+
64+
clone->dst = nl_addr_get(src->dst);
65+
clone->ttl = src->ttl;
66+
67+
return clone;
68+
}
69+
5270
static struct nla_policy mpls_encap_policy[MPLS_IPTUNNEL_MAX + 1] = {
5371
[MPLS_IPTUNNEL_DST] = { .type = NLA_U32 },
5472
[MPLS_IPTUNNEL_TTL] = { .type = NLA_U8 },
@@ -108,6 +126,7 @@ struct nh_encap_ops mpls_encap_ops = {
108126
.build_msg = mpls_encap_build_msg,
109127
.parse_msg = mpls_encap_parse_msg,
110128
.compare = mpls_encap_compare,
129+
.clone = mpls_encap_clone,
111130
.dump = mpls_encap_dump,
112131
.destructor = mpls_encap_destructor,
113132
};

libnl-route-3.sym

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,7 @@ global:
13721372
rtnl_link_is_bond;
13731373
rtnl_nh_add;
13741374
rtnl_nh_encap_alloc;
1375+
rtnl_nh_encap_clone;
13751376
rtnl_nh_encap_free;
13761377
rtnl_nh_encap_mpls;
13771378
rtnl_nh_get_encap_mpls_dst;

tests/cksuite-route-nexthop.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ START_TEST(test_route_nexthop_api_set_get_all)
3636
_nl_auto_nl_addr struct nl_addr *via6 = NULL;
3737
_nl_auto_nl_addr struct nl_addr *mpls = NULL;
3838
_nl_auto_rtnl_nexthop struct rtnl_nexthop *clone = NULL;
39+
_nl_auto_rtnl_nexthop struct rtnl_nexthop *clone_with_encap = NULL;
3940
struct rtnl_nh_encap *encap = NULL;
4041
struct rtnl_nh_encap *got = NULL;
42+
struct rtnl_nh_encap *encap_clone = NULL;
4143
uint32_t realms = 0xAABBCCDDu;
4244
char flags_buf[64];
4345
int flags_parsed;
@@ -141,6 +143,28 @@ START_TEST(test_route_nexthop_api_set_get_all)
141143
ck_assert_ptr_nonnull(rtnl_nh_get_encap_mpls_dst(got));
142144
ck_assert_int_eq(rtnl_nh_get_encap_mpls_ttl(got), 64);
143145

146+
/* Exercise rtnl_nh_encap_clone() directly */
147+
encap_clone = rtnl_nh_encap_clone(encap);
148+
ck_assert_ptr_nonnull(encap_clone);
149+
ck_assert_ptr_nonnull(rtnl_nh_get_encap_mpls_dst(encap_clone));
150+
ck_assert_int_eq(
151+
nl_addr_cmp(rtnl_nh_get_encap_mpls_dst(encap_clone), mpls), 0);
152+
ck_assert_uint_eq(rtnl_nh_get_encap_mpls_ttl(encap_clone), 64);
153+
/* Free the cloned encap explicitly */
154+
rtnl_nh_encap_free(encap_clone);
155+
encap_clone = NULL;
156+
157+
/* Exercise nexthop clone with encap: encap should be deep-cloned */
158+
clone_with_encap = rtnl_route_nh_clone(nh);
159+
ck_assert_ptr_nonnull(clone_with_encap);
160+
encap_clone = rtnl_route_nh_get_encap(clone_with_encap);
161+
ck_assert_ptr_nonnull(encap_clone);
162+
/* The encap on the clone must not be the same pointer */
163+
ck_assert_ptr_ne(encap_clone, encap);
164+
ck_assert_int_eq(
165+
nl_addr_cmp(rtnl_nh_get_encap_mpls_dst(encap_clone), mpls), 0);
166+
ck_assert_uint_eq(rtnl_nh_get_encap_mpls_ttl(encap_clone), 64);
167+
144168
/* Clear encap and verify it is removed */
145169
ck_assert_int_eq(rtnl_route_nh_set_encap(nh, NULL), 0);
146170
ck_assert_ptr_eq(rtnl_route_nh_get_encap(nh), NULL);

0 commit comments

Comments
 (0)