Skip to content

Commit e2f1f07

Browse files
NicolasDichteldavem330
authored andcommitted
sit: allow to configure 6rd tunnels via netlink
This patch add the support of 6RD tunnels management via netlink. Note that netdev_state_change() is now called when 6RD parameters are updated. 6RD parameters are updated only if there is at least one 6RD attribute. Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent e4f67ad commit e2f1f07

File tree

2 files changed

+128
-25
lines changed

2 files changed

+128
-25
lines changed

include/uapi/linux/if_tunnel.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ enum {
4949
IFLA_IPTUN_FLAGS,
5050
IFLA_IPTUN_PROTO,
5151
IFLA_IPTUN_PMTUDISC,
52+
IFLA_IPTUN_6RD_PREFIX,
53+
IFLA_IPTUN_6RD_RELAY_PREFIX,
54+
IFLA_IPTUN_6RD_PREFIXLEN,
55+
IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
5256
__IFLA_IPTUN_MAX,
5357
};
5458
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)

net/ipv6/sit.c

Lines changed: 124 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,38 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
936936
netdev_state_change(t->dev);
937937
}
938938

939+
#ifdef CONFIG_IPV6_SIT_6RD
940+
static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
941+
struct ip_tunnel_6rd *ip6rd)
942+
{
943+
struct in6_addr prefix;
944+
__be32 relay_prefix;
945+
946+
if (ip6rd->relay_prefixlen > 32 ||
947+
ip6rd->prefixlen + (32 - ip6rd->relay_prefixlen) > 64)
948+
return -EINVAL;
949+
950+
ipv6_addr_prefix(&prefix, &ip6rd->prefix, ip6rd->prefixlen);
951+
if (!ipv6_addr_equal(&prefix, &ip6rd->prefix))
952+
return -EINVAL;
953+
if (ip6rd->relay_prefixlen)
954+
relay_prefix = ip6rd->relay_prefix &
955+
htonl(0xffffffffUL <<
956+
(32 - ip6rd->relay_prefixlen));
957+
else
958+
relay_prefix = 0;
959+
if (relay_prefix != ip6rd->relay_prefix)
960+
return -EINVAL;
961+
962+
t->ip6rd.prefix = prefix;
963+
t->ip6rd.relay_prefix = relay_prefix;
964+
t->ip6rd.prefixlen = ip6rd->prefixlen;
965+
t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen;
966+
netdev_state_change(t->dev);
967+
return 0;
968+
}
969+
#endif
970+
939971
static int
940972
ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
941973
{
@@ -1105,31 +1137,9 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
11051137
t = netdev_priv(dev);
11061138

11071139
if (cmd != SIOCDEL6RD) {
1108-
struct in6_addr prefix;
1109-
__be32 relay_prefix;
1110-
1111-
err = -EINVAL;
1112-
if (ip6rd.relay_prefixlen > 32 ||
1113-
ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64)
1114-
goto done;
1115-
1116-
ipv6_addr_prefix(&prefix, &ip6rd.prefix,
1117-
ip6rd.prefixlen);
1118-
if (!ipv6_addr_equal(&prefix, &ip6rd.prefix))
1140+
err = ipip6_tunnel_update_6rd(t, &ip6rd);
1141+
if (err < 0)
11191142
goto done;
1120-
if (ip6rd.relay_prefixlen)
1121-
relay_prefix = ip6rd.relay_prefix &
1122-
htonl(0xffffffffUL <<
1123-
(32 - ip6rd.relay_prefixlen));
1124-
else
1125-
relay_prefix = 0;
1126-
if (relay_prefix != ip6rd.relay_prefix)
1127-
goto done;
1128-
1129-
t->ip6rd.prefix = prefix;
1130-
t->ip6rd.relay_prefix = relay_prefix;
1131-
t->ip6rd.prefixlen = ip6rd.prefixlen;
1132-
t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
11331143
} else
11341144
ipip6_tunnel_clone_6rd(dev, sitn);
11351145

@@ -1261,19 +1271,70 @@ static void ipip6_netlink_parms(struct nlattr *data[],
12611271
parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]);
12621272
}
12631273

1274+
#ifdef CONFIG_IPV6_SIT_6RD
1275+
/* This function returns true when 6RD attributes are present in the nl msg */
1276+
static bool ipip6_netlink_6rd_parms(struct nlattr *data[],
1277+
struct ip_tunnel_6rd *ip6rd)
1278+
{
1279+
bool ret = false;
1280+
memset(ip6rd, 0, sizeof(*ip6rd));
1281+
1282+
if (!data)
1283+
return ret;
1284+
1285+
if (data[IFLA_IPTUN_6RD_PREFIX]) {
1286+
ret = true;
1287+
nla_memcpy(&ip6rd->prefix, data[IFLA_IPTUN_6RD_PREFIX],
1288+
sizeof(struct in6_addr));
1289+
}
1290+
1291+
if (data[IFLA_IPTUN_6RD_RELAY_PREFIX]) {
1292+
ret = true;
1293+
ip6rd->relay_prefix =
1294+
nla_get_be32(data[IFLA_IPTUN_6RD_RELAY_PREFIX]);
1295+
}
1296+
1297+
if (data[IFLA_IPTUN_6RD_PREFIXLEN]) {
1298+
ret = true;
1299+
ip6rd->prefixlen = nla_get_u16(data[IFLA_IPTUN_6RD_PREFIXLEN]);
1300+
}
1301+
1302+
if (data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) {
1303+
ret = true;
1304+
ip6rd->relay_prefixlen =
1305+
nla_get_u16(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
1306+
}
1307+
1308+
return ret;
1309+
}
1310+
#endif
1311+
12641312
static int ipip6_newlink(struct net *src_net, struct net_device *dev,
12651313
struct nlattr *tb[], struct nlattr *data[])
12661314
{
12671315
struct net *net = dev_net(dev);
12681316
struct ip_tunnel *nt;
1317+
#ifdef CONFIG_IPV6_SIT_6RD
1318+
struct ip_tunnel_6rd ip6rd;
1319+
#endif
1320+
int err;
12691321

12701322
nt = netdev_priv(dev);
12711323
ipip6_netlink_parms(data, &nt->parms);
12721324

12731325
if (ipip6_tunnel_locate(net, &nt->parms, 0))
12741326
return -EEXIST;
12751327

1276-
return ipip6_tunnel_create(dev);
1328+
err = ipip6_tunnel_create(dev);
1329+
if (err < 0)
1330+
return err;
1331+
1332+
#ifdef CONFIG_IPV6_SIT_6RD
1333+
if (ipip6_netlink_6rd_parms(data, &ip6rd))
1334+
err = ipip6_tunnel_update_6rd(nt, &ip6rd);
1335+
#endif
1336+
1337+
return err;
12771338
}
12781339

12791340
static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
@@ -1283,6 +1344,9 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
12831344
struct ip_tunnel_parm p;
12841345
struct net *net = dev_net(dev);
12851346
struct sit_net *sitn = net_generic(net, sit_net_id);
1347+
#ifdef CONFIG_IPV6_SIT_6RD
1348+
struct ip_tunnel_6rd ip6rd;
1349+
#endif
12861350

12871351
if (dev == sitn->fb_tunnel_dev)
12881352
return -EINVAL;
@@ -1302,6 +1366,12 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
13021366
t = netdev_priv(dev);
13031367

13041368
ipip6_tunnel_update(t, &p);
1369+
1370+
#ifdef CONFIG_IPV6_SIT_6RD
1371+
if (ipip6_netlink_6rd_parms(data, &ip6rd))
1372+
return ipip6_tunnel_update_6rd(t, &ip6rd);
1373+
#endif
1374+
13051375
return 0;
13061376
}
13071377

@@ -1322,6 +1392,16 @@ static size_t ipip6_get_size(const struct net_device *dev)
13221392
nla_total_size(1) +
13231393
/* IFLA_IPTUN_FLAGS */
13241394
nla_total_size(2) +
1395+
#ifdef CONFIG_IPV6_SIT_6RD
1396+
/* IFLA_IPTUN_6RD_PREFIX */
1397+
nla_total_size(sizeof(struct in6_addr)) +
1398+
/* IFLA_IPTUN_6RD_RELAY_PREFIX */
1399+
nla_total_size(4) +
1400+
/* IFLA_IPTUN_6RD_PREFIXLEN */
1401+
nla_total_size(2) +
1402+
/* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */
1403+
nla_total_size(2) +
1404+
#endif
13251405
0;
13261406
}
13271407

@@ -1339,6 +1419,19 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
13391419
!!(parm->iph.frag_off & htons(IP_DF))) ||
13401420
nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags))
13411421
goto nla_put_failure;
1422+
1423+
#ifdef CONFIG_IPV6_SIT_6RD
1424+
if (nla_put(skb, IFLA_IPTUN_6RD_PREFIX, sizeof(struct in6_addr),
1425+
&tunnel->ip6rd.prefix) ||
1426+
nla_put_be32(skb, IFLA_IPTUN_6RD_RELAY_PREFIX,
1427+
tunnel->ip6rd.relay_prefix) ||
1428+
nla_put_u16(skb, IFLA_IPTUN_6RD_PREFIXLEN,
1429+
tunnel->ip6rd.prefixlen) ||
1430+
nla_put_u16(skb, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
1431+
tunnel->ip6rd.relay_prefixlen))
1432+
goto nla_put_failure;
1433+
#endif
1434+
13421435
return 0;
13431436

13441437
nla_put_failure:
@@ -1353,6 +1446,12 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
13531446
[IFLA_IPTUN_TOS] = { .type = NLA_U8 },
13541447
[IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
13551448
[IFLA_IPTUN_FLAGS] = { .type = NLA_U16 },
1449+
#ifdef CONFIG_IPV6_SIT_6RD
1450+
[IFLA_IPTUN_6RD_PREFIX] = { .len = sizeof(struct in6_addr) },
1451+
[IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 },
1452+
[IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 },
1453+
[IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
1454+
#endif
13561455
};
13571456

13581457
static struct rtnl_link_ops sit_link_ops __read_mostly = {

0 commit comments

Comments
 (0)