History

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.

Nicolas Dichtel committed 13 years ago

Commit e2f1f071 parent e4f67ad2 files · +128 −25Browse files

Unified · Split

2 files
  1. include/uapi/linux/if_tunnel.h +4 −0
  2. net/ipv6/sit.c +124 −25
include/uapi/linux/if_tunnel.h+4−0
@@ -49,6 +49,10 @@ enum { · 48 unmodified lines
4949 IFLA_IPTUN_FLAGS,
5050 IFLA_IPTUN_PROTO,
5151 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,
5256 __IFLA_IPTUN_MAX,
5357 };
5458 #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
net/ipv6/sit.c+124−25
@@ -936,6 +936,38 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) · 935 unmodified lines
936936 netdev_state_change(t->dev);
937937 }
938938
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+
939971 static int
940972 ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
941973 {
@@ -1105,31 +1137,9 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) · 163 unmodified lines
11051137 t = netdev_priv(dev);
11061138
11071139 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)
11191142 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;
11331143 } else
11341144 ipip6_tunnel_clone_6rd(dev, sitn);
11351145
@@ -1261,11 +1271,53 @@ static void ipip6_netlink_parms(struct nlattr *data[], · 125 unmodified lines
12611271 parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]);
12621272 }
12631273
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+
12641312 static int ipip6_newlink(struct net *src_net, struct net_device *dev,
12651313 struct nlattr *tb[], struct nlattr *data[])
12661314 {
12671315 struct net *net = dev_net(dev);
12681316 struct ip_tunnel *nt;
1317+#ifdef CONFIG_IPV6_SIT_6RD
1318+ struct ip_tunnel_6rd ip6rd;
1319+#endif
1320+ int err;
12691321
12701322 nt = netdev_priv(dev);
12711323 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
12731325 if (ipip6_tunnel_locate(net, &nt->parms, 0))
12741326 return -EEXIST;
12751327
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;
12771338 }
12781339
12791340 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
12831344 struct ip_tunnel_parm p;
12841345 struct net *net = dev_net(dev);
12851346 struct sit_net *sitn = net_generic(net, sit_net_id);
1347+#ifdef CONFIG_IPV6_SIT_6RD
1348+ struct ip_tunnel_6rd ip6rd;
1349+#endif
12861350
12871351 if (dev == sitn->fb_tunnel_dev)
12881352 return -EINVAL;
@@ -1302,6 +1366,12 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], · 13 unmodified lines
13021366 t = netdev_priv(dev);
13031367
13041368 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+
13051375 return 0;
13061376 }
13071377
@@ -1322,6 +1392,16 @@ static size_t ipip6_get_size(const struct net_device *dev) · 14 unmodified lines
13221392 nla_total_size(1) +
13231393 /* IFLA_IPTUN_FLAGS */
13241394 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
13251405 0;
13261406 }
13271407
@@ -1339,6 +1419,19 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) · 11 unmodified lines
13391419 !!(parm->iph.frag_off & htons(IP_DF))) ||
13401420 nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags))
13411421 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+
13421435 return 0;
13431436
13441437 nla_put_failure:
@@ -1353,6 +1446,12 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { · 8 unmodified lines
13531446 [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
13541447 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
13551448 [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
13561455 };
13571456
13581457 static struct rtnl_link_ops sit_link_ops __read_mostly = {