Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Nicolas Dichtel and committed by
David S. Miller
e2f1f072 e4f67add

+128 -25
+4
include/uapi/linux/if_tunnel.h
··· 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)
+124 -25
net/ipv6/sit.c
··· 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 { ··· 1137 1105 t = netdev_priv(dev); 1138 1106 1139 1107 if (cmd != SIOCDEL6RD) { 1140 - struct in6_addr prefix; 1141 - __be32 relay_prefix; 1142 - 1143 - err = -EINVAL; 1144 - if (ip6rd.relay_prefixlen > 32 || 1145 - ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64) 1108 + err = ipip6_tunnel_update_6rd(t, &ip6rd); 1109 + if (err < 0) 1146 1110 goto done; 1147 - 1148 - ipv6_addr_prefix(&prefix, &ip6rd.prefix, 1149 - ip6rd.prefixlen); 1150 - if (!ipv6_addr_equal(&prefix, &ip6rd.prefix)) 1151 - goto done; 1152 - if (ip6rd.relay_prefixlen) 1153 - relay_prefix = ip6rd.relay_prefix & 1154 - htonl(0xffffffffUL << 1155 - (32 - ip6rd.relay_prefixlen)); 1156 - else 1157 - relay_prefix = 0; 1158 - if (relay_prefix != ip6rd.relay_prefix) 1159 - goto done; 1160 - 1161 - t->ip6rd.prefix = prefix; 1162 - t->ip6rd.relay_prefix = relay_prefix; 1163 - t->ip6rd.prefixlen = ip6rd.prefixlen; 1164 - t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen; 1165 1111 } else 1166 1112 ipip6_tunnel_clone_6rd(dev, sitn); 1167 1113 ··· 1271 1261 parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]); 1272 1262 } 1273 1263 1264 + #ifdef CONFIG_IPV6_SIT_6RD 1265 + /* This function returns true when 6RD attributes are present in the nl msg */ 1266 + static bool ipip6_netlink_6rd_parms(struct nlattr *data[], 1267 + struct ip_tunnel_6rd *ip6rd) 1268 + { 1269 + bool ret = false; 1270 + memset(ip6rd, 0, sizeof(*ip6rd)); 1271 + 1272 + if (!data) 1273 + return ret; 1274 + 1275 + if (data[IFLA_IPTUN_6RD_PREFIX]) { 1276 + ret = true; 1277 + nla_memcpy(&ip6rd->prefix, data[IFLA_IPTUN_6RD_PREFIX], 1278 + sizeof(struct in6_addr)); 1279 + } 1280 + 1281 + if (data[IFLA_IPTUN_6RD_RELAY_PREFIX]) { 1282 + ret = true; 1283 + ip6rd->relay_prefix = 1284 + nla_get_be32(data[IFLA_IPTUN_6RD_RELAY_PREFIX]); 1285 + } 1286 + 1287 + if (data[IFLA_IPTUN_6RD_PREFIXLEN]) { 1288 + ret = true; 1289 + ip6rd->prefixlen = nla_get_u16(data[IFLA_IPTUN_6RD_PREFIXLEN]); 1290 + } 1291 + 1292 + if (data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) { 1293 + ret = true; 1294 + ip6rd->relay_prefixlen = 1295 + nla_get_u16(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); 1296 + } 1297 + 1298 + return ret; 1299 + } 1300 + #endif 1301 + 1274 1302 static int ipip6_newlink(struct net *src_net, struct net_device *dev, 1275 1303 struct nlattr *tb[], struct nlattr *data[]) 1276 1304 { 1277 1305 struct net *net = dev_net(dev); 1278 1306 struct ip_tunnel *nt; 1307 + #ifdef CONFIG_IPV6_SIT_6RD 1308 + struct ip_tunnel_6rd ip6rd; 1309 + #endif 1310 + int err; 1279 1311 1280 1312 nt = netdev_priv(dev); 1281 1313 ipip6_netlink_parms(data, &nt->parms); ··· 1325 1273 if (ipip6_tunnel_locate(net, &nt->parms, 0)) 1326 1274 return -EEXIST; 1327 1275 1328 - return ipip6_tunnel_create(dev); 1276 + err = ipip6_tunnel_create(dev); 1277 + if (err < 0) 1278 + return err; 1279 + 1280 + #ifdef CONFIG_IPV6_SIT_6RD 1281 + if (ipip6_netlink_6rd_parms(data, &ip6rd)) 1282 + err = ipip6_tunnel_update_6rd(nt, &ip6rd); 1283 + #endif 1284 + 1285 + return err; 1329 1286 } 1330 1287 1331 1288 static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], ··· 1344 1283 struct ip_tunnel_parm p; 1345 1284 struct net *net = dev_net(dev); 1346 1285 struct sit_net *sitn = net_generic(net, sit_net_id); 1286 + #ifdef CONFIG_IPV6_SIT_6RD 1287 + struct ip_tunnel_6rd ip6rd; 1288 + #endif 1347 1289 1348 1290 if (dev == sitn->fb_tunnel_dev) 1349 1291 return -EINVAL; ··· 1366 1302 t = netdev_priv(dev); 1367 1303 1368 1304 ipip6_tunnel_update(t, &p); 1305 + 1306 + #ifdef CONFIG_IPV6_SIT_6RD 1307 + if (ipip6_netlink_6rd_parms(data, &ip6rd)) 1308 + return ipip6_tunnel_update_6rd(t, &ip6rd); 1309 + #endif 1310 + 1369 1311 return 0; 1370 1312 } 1371 1313 ··· 1392 1322 nla_total_size(1) + 1393 1323 /* IFLA_IPTUN_FLAGS */ 1394 1324 nla_total_size(2) + 1325 + #ifdef CONFIG_IPV6_SIT_6RD 1326 + /* IFLA_IPTUN_6RD_PREFIX */ 1327 + nla_total_size(sizeof(struct in6_addr)) + 1328 + /* IFLA_IPTUN_6RD_RELAY_PREFIX */ 1329 + nla_total_size(4) + 1330 + /* IFLA_IPTUN_6RD_PREFIXLEN */ 1331 + nla_total_size(2) + 1332 + /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */ 1333 + nla_total_size(2) + 1334 + #endif 1395 1335 0; 1396 1336 } 1397 1337 ··· 1419 1339 !!(parm->iph.frag_off & htons(IP_DF))) || 1420 1340 nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags)) 1421 1341 goto nla_put_failure; 1342 + 1343 + #ifdef CONFIG_IPV6_SIT_6RD 1344 + if (nla_put(skb, IFLA_IPTUN_6RD_PREFIX, sizeof(struct in6_addr), 1345 + &tunnel->ip6rd.prefix) || 1346 + nla_put_be32(skb, IFLA_IPTUN_6RD_RELAY_PREFIX, 1347 + tunnel->ip6rd.relay_prefix) || 1348 + nla_put_u16(skb, IFLA_IPTUN_6RD_PREFIXLEN, 1349 + tunnel->ip6rd.prefixlen) || 1350 + nla_put_u16(skb, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, 1351 + tunnel->ip6rd.relay_prefixlen)) 1352 + goto nla_put_failure; 1353 + #endif 1354 + 1422 1355 return 0; 1423 1356 1424 1357 nla_put_failure: ··· 1446 1353 [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, 1447 1354 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, 1448 1355 [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, 1356 + #ifdef CONFIG_IPV6_SIT_6RD 1357 + [IFLA_IPTUN_6RD_PREFIX] = { .len = sizeof(struct in6_addr) }, 1358 + [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 }, 1359 + [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, 1360 + [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, 1361 + #endif 1449 1362 }; 1450 1363 1451 1364 static struct rtnl_link_ops sit_link_ops __read_mostly = {