Skip to content

Commit c8f66f7

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

File tree

7 files changed

+84
-17
lines changed

7 files changed

+84
-17
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+
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: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,32 +65,34 @@ struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
6565

6666
if (src->rtnh_gateway) {
6767
nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
68-
if (!nh->rtnh_gateway) {
69-
free(nh);
70-
return NULL;
71-
}
68+
if (!nh->rtnh_gateway)
69+
goto err;
7270
}
7371

7472
if (src->rtnh_newdst) {
7573
nh->rtnh_newdst = nl_addr_clone(src->rtnh_newdst);
76-
if (!nh->rtnh_newdst) {
77-
nl_addr_put(nh->rtnh_gateway);
78-
free(nh);
79-
return NULL;
80-
}
74+
if (!nh->rtnh_newdst)
75+
goto err;
8176
}
8277

8378
if (src->rtnh_via) {
8479
nh->rtnh_via = nl_addr_clone(src->rtnh_via);
85-
if (!nh->rtnh_via) {
86-
nl_addr_put(nh->rtnh_gateway);
87-
nl_addr_put(nh->rtnh_newdst);
88-
free(nh);
89-
return NULL;
90-
}
80+
if (!nh->rtnh_via)
81+
goto err;
82+
}
83+
84+
/* Clone encapsulation information if present */
85+
if (src->rtnh_encap) {
86+
nh->rtnh_encap = rtnl_nh_encap_clone(src->rtnh_encap);
87+
if (!nh->rtnh_encap)
88+
goto err;
9189
}
9290

9391
return nh;
92+
93+
err:
94+
rtnl_route_nh_free(nh);
95+
return NULL;
9496
}
9597

9698
void rtnl_route_nh_free(struct rtnl_nexthop *nh)

lib/route/nh.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,26 @@ 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+
struct rtnl_nh_encap *new_encap;
675+
676+
new_encap = rtnl_nh_encap_alloc();
677+
if (!new_encap)
678+
return NULL;
679+
680+
new_encap->ops = src->ops;
681+
if (new_encap->ops && new_encap->ops->clone) {
682+
new_encap->priv = new_encap->ops->clone(src->priv);
683+
if (!new_encap->priv) {
684+
rtnl_nh_encap_free(new_encap);
685+
return NULL;
686+
}
687+
}
688+
689+
return new_encap;
690+
}
691+
672692
/*
673693
* Retrieve the encapsulation associated with a nexthop if any.
674694
*/

lib/route/nh_encap_mpls.c

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

50+
static void *mpls_encap_clone(void *priv)
51+
{
52+
struct mpls_iptunnel_encap *src = priv;
53+
struct mpls_iptunnel_encap *clone;
54+
55+
if (!src)
56+
return NULL;
57+
58+
clone = calloc(1, sizeof(*clone));
59+
if (!clone)
60+
return NULL;
61+
62+
clone->dst = nl_addr_get(src->dst);
63+
clone->ttl = src->ttl;
64+
65+
return clone;
66+
}
67+
5068
static struct nla_policy mpls_encap_policy[MPLS_IPTUNNEL_MAX + 1] = {
5169
[MPLS_IPTUNNEL_DST] = { .type = NLA_U32 },
5270
[MPLS_IPTUNNEL_TTL] = { .type = NLA_U8 },
@@ -118,6 +136,7 @@ struct nh_encap_ops mpls_encap_ops = {
118136
.build_msg = mpls_encap_build_msg,
119137
.parse_msg = mpls_encap_parse_msg,
120138
.compare = mpls_encap_compare,
139+
.clone = mpls_encap_clone,
121140
.dump = mpls_encap_dump,
122141
.destructor = mpls_encap_destructor,
123142
};

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: 25 additions & 2 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;
@@ -123,8 +125,7 @@ START_TEST(test_route_nexthop_api_set_get_all)
123125
ck_assert_ptr_nonnull(encap);
124126

125127
/* Invalid: missing destination labels */
126-
ck_assert_int_eq(rtnl_nh_encap_mpls(encap, NULL, 0),
127-
-NLE_INVAL);
128+
ck_assert_int_eq(rtnl_nh_encap_mpls(encap, NULL, 0), -NLE_INVAL);
128129

129130
/* Valid MPLS encap: push label 100 with TTL 64 */
130131
ck_assert_int_eq(nl_addr_parse("100", AF_MPLS, &mpls), 0);
@@ -139,6 +140,28 @@ START_TEST(test_route_nexthop_api_set_get_all)
139140
ck_assert_ptr_nonnull(rtnl_nh_get_encap_mpls_dst(got));
140141
ck_assert_uint_eq(rtnl_nh_get_encap_mpls_ttl(got), 64);
141142

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

0 commit comments

Comments
 (0)