diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2012-11-14 00:14:03 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-14 22:02:38 -0500 |
commit | be42da0e1012bf67d8f6899b7d9162e35527da4b (patch) | |
tree | c8a7a4c667d6ac8aa9fa911f6b67739a742696c9 /net/ipv4/ipip.c | |
parent | befe2aa1b2c7b9b7e20e97906f99b58475608867 (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.c | 165 |
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 | ||
252 | static 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 | |||
274 | out: | ||
275 | return err; | ||
276 | } | ||
277 | |||
252 | static struct ip_tunnel *ipip_tunnel_locate(struct net *net, | 278 | static 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 | ||
299 | failed_free: | 317 | failed_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 | ||
643 | static 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 | |||
625 | static int | 665 | static int |
626 | ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | 666 | ipip_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 | ||
851 | static 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 | |||
885 | static 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 | |||
900 | static 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 | |||
825 | static size_t ipip_get_size(const struct net_device *dev) | 929 | static 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 | ||
966 | static 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 | |||
862 | static struct rtnl_link_ops ipip_link_ops __read_mostly = { | 975 | static 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 | }; |