diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2012-11-19 17:41:45 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-20 13:43:28 -0500 |
commit | e2f1f072db8db81e6b5bcbfcf409bb5c91dc9329 (patch) | |
tree | a19138de5bf57a0dab684a44fc214cf1f2833846 | |
parent | e4f67addf158f98f8197e08974966b18480dc751 (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.h | 4 | ||||
-rw-r--r-- | net/ipv6/sit.c | 149 |
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 | ||
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 | |||
939 | static int | 971 | static int |
940 | ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | 972 | ipip6_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 */ | ||
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 | |||
1264 | static int ipip6_newlink(struct net *src_net, struct net_device *dev, | 1312 | static 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 | ||
1279 | static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], | 1340 | 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[], | |||
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 | ||
1344 | nla_put_failure: | 1437 | nla_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 | ||
1358 | static struct rtnl_link_ops sit_link_ops __read_mostly = { | 1457 | static struct rtnl_link_ops sit_link_ops __read_mostly = { |