aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipip.c
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2012-11-14 00:14:03 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-14 22:02:38 -0500
commitbe42da0e1012bf67d8f6899b7d9162e35527da4b (patch)
treec8a7a4c667d6ac8aa9fa911f6b67739a742696c9 /net/ipv4/ipip.c
parentbefe2aa1b2c7b9b7e20e97906f99b58475608867 (diff)
ipip: add support of link creation via rtnl
This patch add the support of 'ip link .. type ipip'. Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ipip.c')
-rw-r--r--net/ipv4/ipip.c165
1 files changed, 141 insertions, 24 deletions
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 1fc0ea4786b9..64686e1f54d9 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -249,6 +249,32 @@ static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
249 rcu_assign_pointer(*tp, t); 249 rcu_assign_pointer(*tp, t);
250} 250}
251 251
252static int ipip_tunnel_create(struct net_device *dev)
253{
254 struct ip_tunnel *t = netdev_priv(dev);
255 struct net *net = dev_net(dev);
256 struct ipip_net *ipn = net_generic(net, ipip_net_id);
257 int err;
258
259 err = ipip_tunnel_init(dev);
260 if (err < 0)
261 goto out;
262
263 err = register_netdevice(dev);
264 if (err < 0)
265 goto out;
266
267 strcpy(t->parms.name, dev->name);
268 dev->rtnl_link_ops = &ipip_link_ops;
269
270 dev_hold(dev);
271 ipip_tunnel_link(ipn, t);
272 return 0;
273
274out:
275 return err;
276}
277
252static struct ip_tunnel *ipip_tunnel_locate(struct net *net, 278static struct ip_tunnel *ipip_tunnel_locate(struct net *net,
253 struct ip_tunnel_parm *parms, int create) 279 struct ip_tunnel_parm *parms, int create)
254{ 280{
@@ -283,17 +309,9 @@ static struct ip_tunnel *ipip_tunnel_locate(struct net *net,
283 nt = netdev_priv(dev); 309 nt = netdev_priv(dev);
284 nt->parms = *parms; 310 nt->parms = *parms;
285 311
286 if (ipip_tunnel_init(dev) < 0) 312 if (ipip_tunnel_create(dev) < 0)
287 goto failed_free; 313 goto failed_free;
288 314
289 if (register_netdevice(dev) < 0)
290 goto failed_free;
291
292 strcpy(nt->parms.name, dev->name);
293 dev->rtnl_link_ops = &ipip_link_ops;
294
295 dev_hold(dev);
296 ipip_tunnel_link(ipn, nt);
297 return nt; 315 return nt;
298 316
299failed_free: 317failed_free:
@@ -622,6 +640,28 @@ static void ipip_tunnel_bind_dev(struct net_device *dev)
622 dev->iflink = tunnel->parms.link; 640 dev->iflink = tunnel->parms.link;
623} 641}
624 642
643static void ipip_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
644{
645 struct net *net = dev_net(t->dev);
646 struct ipip_net *ipn = net_generic(net, ipip_net_id);
647
648 ipip_tunnel_unlink(ipn, t);
649 synchronize_net();
650 t->parms.iph.saddr = p->iph.saddr;
651 t->parms.iph.daddr = p->iph.daddr;
652 memcpy(t->dev->dev_addr, &p->iph.saddr, 4);
653 memcpy(t->dev->broadcast, &p->iph.daddr, 4);
654 ipip_tunnel_link(ipn, t);
655 t->parms.iph.ttl = p->iph.ttl;
656 t->parms.iph.tos = p->iph.tos;
657 t->parms.iph.frag_off = p->iph.frag_off;
658 if (t->parms.link != p->link) {
659 t->parms.link = p->link;
660 ipip_tunnel_bind_dev(t->dev);
661 }
662 netdev_state_change(t->dev);
663}
664
625static int 665static int
626ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) 666ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
627{ 667{
@@ -682,21 +722,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
682 t = netdev_priv(dev); 722 t = netdev_priv(dev);
683 } 723 }
684 724
685 ipip_tunnel_unlink(ipn, t); 725 ipip_tunnel_update(t, &p);
686 synchronize_net();
687 t->parms.iph.saddr = p.iph.saddr;
688 t->parms.iph.daddr = p.iph.daddr;
689 memcpy(dev->dev_addr, &p.iph.saddr, 4);
690 memcpy(dev->broadcast, &p.iph.daddr, 4);
691 ipip_tunnel_link(ipn, t);
692 t->parms.iph.ttl = p.iph.ttl;
693 t->parms.iph.tos = p.iph.tos;
694 t->parms.iph.frag_off = p.iph.frag_off;
695 if (t->parms.link != p.link) {
696 t->parms.link = p.link;
697 ipip_tunnel_bind_dev(dev);
698 }
699 netdev_state_change(dev);
700 } 726 }
701 727
702 if (t) { 728 if (t) {
@@ -822,6 +848,84 @@ static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
822 return 0; 848 return 0;
823} 849}
824 850
851static void ipip_netlink_parms(struct nlattr *data[],
852 struct ip_tunnel_parm *parms)
853{
854 memset(parms, 0, sizeof(*parms));
855
856 parms->iph.version = 4;
857 parms->iph.protocol = IPPROTO_IPIP;
858 parms->iph.ihl = 5;
859
860 if (!data)
861 return;
862
863 if (data[IFLA_IPTUN_LINK])
864 parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]);
865
866 if (data[IFLA_IPTUN_LOCAL])
867 parms->iph.saddr = nla_get_u32(data[IFLA_IPTUN_LOCAL]);
868
869 if (data[IFLA_IPTUN_REMOTE])
870 parms->iph.daddr = nla_get_u32(data[IFLA_IPTUN_REMOTE]);
871
872 if (data[IFLA_IPTUN_TTL]) {
873 parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]);
874 if (parms->iph.ttl)
875 parms->iph.frag_off = htons(IP_DF);
876 }
877
878 if (data[IFLA_IPTUN_TOS])
879 parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
880
881 if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
882 parms->iph.frag_off = htons(IP_DF);
883}
884
885static int ipip_newlink(struct net *src_net, struct net_device *dev,
886 struct nlattr *tb[], struct nlattr *data[])
887{
888 struct net *net = dev_net(dev);
889 struct ip_tunnel *nt;
890
891 nt = netdev_priv(dev);
892 ipip_netlink_parms(data, &nt->parms);
893
894 if (ipip_tunnel_locate(net, &nt->parms, 0))
895 return -EEXIST;
896
897 return ipip_tunnel_create(dev);
898}
899
900static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
901 struct nlattr *data[])
902{
903 struct ip_tunnel *t;
904 struct ip_tunnel_parm p;
905 struct net *net = dev_net(dev);
906 struct ipip_net *ipn = net_generic(net, ipip_net_id);
907
908 if (dev == ipn->fb_tunnel_dev)
909 return -EINVAL;
910
911 ipip_netlink_parms(data, &p);
912
913 if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) ||
914 (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
915 return -EINVAL;
916
917 t = ipip_tunnel_locate(net, &p, 0);
918
919 if (t) {
920 if (t->dev != dev)
921 return -EEXIST;
922 } else
923 t = netdev_priv(dev);
924
925 ipip_tunnel_update(t, &p);
926 return 0;
927}
928
825static size_t ipip_get_size(const struct net_device *dev) 929static size_t ipip_get_size(const struct net_device *dev)
826{ 930{
827 return 931 return
@@ -859,10 +963,23 @@ nla_put_failure:
859 return -EMSGSIZE; 963 return -EMSGSIZE;
860} 964}
861 965
966static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
967 [IFLA_IPTUN_LINK] = { .type = NLA_U32 },
968 [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 },
969 [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
970 [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
971 [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
972 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
973};
974
862static struct rtnl_link_ops ipip_link_ops __read_mostly = { 975static struct rtnl_link_ops ipip_link_ops __read_mostly = {
863 .kind = "ipip", 976 .kind = "ipip",
864 .maxtype = IFLA_IPTUN_MAX, 977 .maxtype = IFLA_IPTUN_MAX,
978 .policy = ipip_policy,
865 .priv_size = sizeof(struct ip_tunnel), 979 .priv_size = sizeof(struct ip_tunnel),
980 .setup = ipip_tunnel_setup,
981 .newlink = ipip_newlink,
982 .changelink = ipip_changelink,
866 .get_size = ipip_get_size, 983 .get_size = ipip_get_size,
867 .fill_info = ipip_fill_info, 984 .fill_info = ipip_fill_info,
868}; 985};