aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2012-11-19 17:41:45 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-20 13:43:28 -0500
commite2f1f072db8db81e6b5bcbfcf409bb5c91dc9329 (patch)
treea19138de5bf57a0dab684a44fc214cf1f2833846
parente4f67addf158f98f8197e08974966b18480dc751 (diff)
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>
-rw-r--r--include/uapi/linux/if_tunnel.h4
-rw-r--r--net/ipv6/sit.c149
2 files changed, 128 insertions, 25 deletions
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index 5ab0c8ddc2bc..aee73d0611fb 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -49,6 +49,10 @@ enum {
49 IFLA_IPTUN_FLAGS, 49 IFLA_IPTUN_FLAGS,
50 IFLA_IPTUN_PROTO, 50 IFLA_IPTUN_PROTO,
51 IFLA_IPTUN_PMTUDISC, 51 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,
52 __IFLA_IPTUN_MAX, 56 __IFLA_IPTUN_MAX,
53}; 57};
54#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) 58#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index fee21c6c3ebf..80cb3829831c 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -936,6 +936,38 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
936 netdev_state_change(t->dev); 936 netdev_state_change(t->dev);
937} 937}
938 938
939#ifdef CONFIG_IPV6_SIT_6RD
940static 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
939static int 971static int
940ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) 972ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
941{ 973{
@@ -1105,31 +1137,9 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
1105 t = netdev_priv(dev); 1137 t = netdev_priv(dev);
1106 1138
1107 if (cmd != SIOCDEL6RD) { 1139 if (cmd != SIOCDEL6RD) {
1108 struct in6_addr prefix; 1140 err = ipip6_tunnel_update_6rd(t, &ip6rd);
1109 __be32 relay_prefix; 1141 if (err < 0)
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))
1119 goto done; 1142 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;
1133 } else 1143 } else
1134 ipip6_tunnel_clone_6rd(dev, sitn); 1144 ipip6_tunnel_clone_6rd(dev, sitn);
1135 1145
@@ -1261,11 +1271,53 @@ static void ipip6_netlink_parms(struct nlattr *data[],
1261 parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]); 1271 parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]);
1262} 1272}
1263 1273
1274#ifdef CONFIG_IPV6_SIT_6RD
1275/* This function returns true when 6RD attributes are present in the nl msg */
1276static 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
1264static int ipip6_newlink(struct net *src_net, struct net_device *dev, 1312static int ipip6_newlink(struct net *src_net, struct net_device *dev,
1265 struct nlattr *tb[], struct nlattr *data[]) 1313 struct nlattr *tb[], struct nlattr *data[])
1266{ 1314{
1267 struct net *net = dev_net(dev); 1315 struct net *net = dev_net(dev);
1268 struct ip_tunnel *nt; 1316 struct ip_tunnel *nt;
1317#ifdef CONFIG_IPV6_SIT_6RD
1318 struct ip_tunnel_6rd ip6rd;
1319#endif
1320 int err;
1269 1321
1270 nt = netdev_priv(dev); 1322 nt = netdev_priv(dev);
1271 ipip6_netlink_parms(data, &nt->parms); 1323 ipip6_netlink_parms(data, &nt->parms);
@@ -1273,7 +1325,16 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
1273 if (ipip6_tunnel_locate(net, &nt->parms, 0)) 1325 if (ipip6_tunnel_locate(net, &nt->parms, 0))
1274 return -EEXIST; 1326 return -EEXIST;
1275 1327
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;
1277} 1338}
1278 1339
1279static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], 1340static 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[],
1283 struct ip_tunnel_parm p; 1344 struct ip_tunnel_parm p;
1284 struct net *net = dev_net(dev); 1345 struct net *net = dev_net(dev);
1285 struct sit_net *sitn = net_generic(net, sit_net_id); 1346 struct sit_net *sitn = net_generic(net, sit_net_id);
1347#ifdef CONFIG_IPV6_SIT_6RD
1348 struct ip_tunnel_6rd ip6rd;
1349#endif
1286 1350
1287 if (dev == sitn->fb_tunnel_dev) 1351 if (dev == sitn->fb_tunnel_dev)
1288 return -EINVAL; 1352 return -EINVAL;
@@ -1302,6 +1366,12 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[],
1302 t = netdev_priv(dev); 1366 t = netdev_priv(dev);
1303 1367
1304 ipip6_tunnel_update(t, &p); 1368 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
1305 return 0; 1375 return 0;
1306} 1376}
1307 1377
@@ -1322,6 +1392,16 @@ static size_t ipip6_get_size(const struct net_device *dev)
1322 nla_total_size(1) + 1392 nla_total_size(1) +
1323 /* IFLA_IPTUN_FLAGS */ 1393 /* IFLA_IPTUN_FLAGS */
1324 nla_total_size(2) + 1394 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
1325 0; 1405 0;
1326} 1406}
1327 1407
@@ -1339,6 +1419,19 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev)
1339 !!(parm->iph.frag_off & htons(IP_DF))) || 1419 !!(parm->iph.frag_off & htons(IP_DF))) ||
1340 nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags)) 1420 nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags))
1341 goto nla_put_failure; 1421 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
1342 return 0; 1435 return 0;
1343 1436
1344nla_put_failure: 1437nla_put_failure:
@@ -1353,6 +1446,12 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = {
1353 [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 1446 [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
1354 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 1447 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
1355 [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, 1448 [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
1356}; 1455};
1357 1456
1358static struct rtnl_link_ops sit_link_ops __read_mostly = { 1457static struct rtnl_link_ops sit_link_ops __read_mostly = {