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.
Unified · Split
| @@ -49,6 +49,10 @@ enum { · 48 unmodified lines | ||
| 49 | 49 | IFLA_IPTUN_FLAGS, |
| 50 | 50 | IFLA_IPTUN_PROTO, |
| 51 | 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 | 56 | __IFLA_IPTUN_MAX, |
| 53 | 57 | }; |
| 54 | 58 | #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) |
| @@ -936,6 +936,38 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) · 935 unmodified lines | ||
| 936 | 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 | 971 | static int |
| 940 | 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) · 163 unmodified lines | ||
| 1105 | 1137 | t = netdev_priv(dev); |
| 1106 | 1138 | |
| 1107 | 1139 | 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) | |
| 1119 | 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 | 1143 | } else |
| 1134 | 1144 | ipip6_tunnel_clone_6rd(dev, sitn); |
| 1135 | 1145 | |
| @@ -1261,11 +1271,53 @@ static void ipip6_netlink_parms(struct nlattr *data[], · 125 unmodified lines | ||
| 1261 | 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 | 1312 | static int ipip6_newlink(struct net *src_net, struct net_device *dev, |
| 1265 | 1313 | struct nlattr *tb[], struct nlattr *data[]) |
| 1266 | 1314 | { |
| 1267 | 1315 | struct net *net = dev_net(dev); |
| 1268 | 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 | 1322 | nt = netdev_priv(dev); |
| 1271 | 1323 | ipip6_netlink_parms(data, &nt->parms); |
| @@ -1273,7 +1325,16 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev, · 1 unmodified line | ||
| 1273 | 1325 | if (ipip6_tunnel_locate(net, &nt->parms, 0)) |
| 1274 | 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 | 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[], · 3 unmodified lines | ||
| 1283 | 1344 | struct ip_tunnel_parm p; |
| 1284 | 1345 | struct net *net = dev_net(dev); |
| 1285 | 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 | 1351 | if (dev == sitn->fb_tunnel_dev) |
| 1288 | 1352 | return -EINVAL; |
| @@ -1302,6 +1366,12 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], · 13 unmodified lines | ||
| 1302 | 1366 | t = netdev_priv(dev); |
| 1303 | 1367 | |
| 1304 | 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 | 1375 | return 0; |
| 1306 | 1376 | } |
| 1307 | 1377 | |
| @@ -1322,6 +1392,16 @@ static size_t ipip6_get_size(const struct net_device *dev) · 14 unmodified lines | ||
| 1322 | 1392 | nla_total_size(1) + |
| 1323 | 1393 | /* IFLA_IPTUN_FLAGS */ |
| 1324 | 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 | 1405 | 0; |
| 1326 | 1406 | } |
| 1327 | 1407 | |
| @@ -1339,6 +1419,19 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) · 11 unmodified lines | ||
| 1339 | 1419 | !!(parm->iph.frag_off & htons(IP_DF))) || |
| 1340 | 1420 | nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags)) |
| 1341 | 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 | 1435 | return 0; |
| 1343 | 1436 | |
| 1344 | 1437 | nla_put_failure: |
| @@ -1353,6 +1446,12 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { · 8 unmodified lines | ||
| 1353 | 1446 | [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, |
| 1354 | 1447 | [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, |
| 1355 | 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 | 1457 | static struct rtnl_link_ops sit_link_ops __read_mostly = { |