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 /net/ipv6 | |
| 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>
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/sit.c | 149 |
1 files changed, 124 insertions, 25 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index fee21c6c3eb..80cb3829831 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 = { |
