aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-01-24 04:41:41 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-29 13:59:57 -0500
commit5c766d642bcaffd0c2a5b354db2068515b3846cf (patch)
treef5bb2ed37d70c79304c17911de77779ea92c1041 /net/ipv4
parent5a1dc31708701e54db1b2bb80215c67d61505d3e (diff)
ipv4: introduce address lifetime
There are some usecase when lifetime of ipv4 addresses might be helpful. For example: 1) initramfs networkmanager uses a DHCP daemon to learn network configuration parameters 2) initramfs networkmanager addresses, routes and DNS configuration 3) initramfs networkmanager is requested to stop 4) initramfs networkmanager stops all daemons including dhclient 5) there are addresses and routes configured but no daemon running. If the system doesn't start networkmanager for some reason, addresses and routes will be used forever, which violates RFC 2131. This patch is essentially a backport of ivp6 address lifetime mechanism for ipv4 addresses. Current "ip" tool supports this without any patch (since it does not distinguish between ipv4 and ipv6 addresses in this perspective. Also, this should be back-compatible with all current netlink users. Reported-by: Pavel Šimerda <psimerda@redhat.com> Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/devinet.c215
1 files changed, 210 insertions, 5 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index a8e4f2665d5e..5281314886c1 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -63,6 +63,7 @@
63#include <net/ip_fib.h> 63#include <net/ip_fib.h>
64#include <net/rtnetlink.h> 64#include <net/rtnetlink.h>
65#include <net/net_namespace.h> 65#include <net/net_namespace.h>
66#include <net/addrconf.h>
66 67
67#include "fib_lookup.h" 68#include "fib_lookup.h"
68 69
@@ -93,6 +94,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
93 [IFA_ADDRESS] = { .type = NLA_U32 }, 94 [IFA_ADDRESS] = { .type = NLA_U32 },
94 [IFA_BROADCAST] = { .type = NLA_U32 }, 95 [IFA_BROADCAST] = { .type = NLA_U32 },
95 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, 96 [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
97 [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
96}; 98};
97 99
98#define IN4_ADDR_HSIZE_SHIFT 8 100#define IN4_ADDR_HSIZE_SHIFT 8
@@ -417,6 +419,10 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
417 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); 419 __inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
418} 420}
419 421
422static void check_lifetime(struct work_struct *work);
423
424static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
425
420static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, 426static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
421 u32 portid) 427 u32 portid)
422{ 428{
@@ -462,6 +468,9 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
462 468
463 inet_hash_insert(dev_net(in_dev->dev), ifa); 469 inet_hash_insert(dev_net(in_dev->dev), ifa);
464 470
471 cancel_delayed_work(&check_lifetime_work);
472 schedule_delayed_work(&check_lifetime_work, 0);
473
465 /* Send message first, then call notifier. 474 /* Send message first, then call notifier.
466 Notifier will trigger FIB update, so that 475 Notifier will trigger FIB update, so that
467 listeners of netlink will know about new ifaddr */ 476 listeners of netlink will know about new ifaddr */
@@ -573,7 +582,107 @@ errout:
573 return err; 582 return err;
574} 583}
575 584
576static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh) 585#define INFINITY_LIFE_TIME 0xFFFFFFFF
586
587static void check_lifetime(struct work_struct *work)
588{
589 unsigned long now, next, next_sec, next_sched;
590 struct in_ifaddr *ifa;
591 struct hlist_node *node;
592 int i;
593
594 now = jiffies;
595 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
596
597 rcu_read_lock();
598 for (i = 0; i < IN4_ADDR_HSIZE; i++) {
599 hlist_for_each_entry_rcu(ifa, node,
600 &inet_addr_lst[i], hash) {
601 unsigned long age;
602
603 if (ifa->ifa_flags & IFA_F_PERMANENT)
604 continue;
605
606 /* We try to batch several events at once. */
607 age = (now - ifa->ifa_tstamp +
608 ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
609
610 if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
611 age >= ifa->ifa_valid_lft) {
612 struct in_ifaddr **ifap ;
613
614 rtnl_lock();
615 for (ifap = &ifa->ifa_dev->ifa_list;
616 *ifap != NULL; ifap = &ifa->ifa_next) {
617 if (*ifap == ifa)
618 inet_del_ifa(ifa->ifa_dev,
619 ifap, 1);
620 }
621 rtnl_unlock();
622 } else if (ifa->ifa_preferred_lft ==
623 INFINITY_LIFE_TIME) {
624 continue;
625 } else if (age >= ifa->ifa_preferred_lft) {
626 if (time_before(ifa->ifa_tstamp +
627 ifa->ifa_valid_lft * HZ, next))
628 next = ifa->ifa_tstamp +
629 ifa->ifa_valid_lft * HZ;
630
631 if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) {
632 ifa->ifa_flags |= IFA_F_DEPRECATED;
633 rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
634 }
635 } else if (time_before(ifa->ifa_tstamp +
636 ifa->ifa_preferred_lft * HZ,
637 next)) {
638 next = ifa->ifa_tstamp +
639 ifa->ifa_preferred_lft * HZ;
640 }
641 }
642 }
643 rcu_read_unlock();
644
645 next_sec = round_jiffies_up(next);
646 next_sched = next;
647
648 /* If rounded timeout is accurate enough, accept it. */
649 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
650 next_sched = next_sec;
651
652 now = jiffies;
653 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
654 if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX))
655 next_sched = now + ADDRCONF_TIMER_FUZZ_MAX;
656
657 schedule_delayed_work(&check_lifetime_work, next_sched - now);
658}
659
660static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft,
661 __u32 prefered_lft)
662{
663 unsigned long timeout;
664
665 ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED);
666
667 timeout = addrconf_timeout_fixup(valid_lft, HZ);
668 if (addrconf_finite_timeout(timeout))
669 ifa->ifa_valid_lft = timeout;
670 else
671 ifa->ifa_flags |= IFA_F_PERMANENT;
672
673 timeout = addrconf_timeout_fixup(prefered_lft, HZ);
674 if (addrconf_finite_timeout(timeout)) {
675 if (timeout == 0)
676 ifa->ifa_flags |= IFA_F_DEPRECATED;
677 ifa->ifa_preferred_lft = timeout;
678 }
679 ifa->ifa_tstamp = jiffies;
680 if (!ifa->ifa_cstamp)
681 ifa->ifa_cstamp = ifa->ifa_tstamp;
682}
683
684static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
685 __u32 *pvalid_lft, __u32 *pprefered_lft)
577{ 686{
578 struct nlattr *tb[IFA_MAX+1]; 687 struct nlattr *tb[IFA_MAX+1];
579 struct in_ifaddr *ifa; 688 struct in_ifaddr *ifa;
@@ -633,24 +742,73 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
633 else 742 else
634 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 743 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
635 744
745 if (tb[IFA_CACHEINFO]) {
746 struct ifa_cacheinfo *ci;
747
748 ci = nla_data(tb[IFA_CACHEINFO]);
749 if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
750 err = -EINVAL;
751 goto errout;
752 }
753 *pvalid_lft = ci->ifa_valid;
754 *pprefered_lft = ci->ifa_prefered;
755 }
756
636 return ifa; 757 return ifa;
637 758
638errout: 759errout:
639 return ERR_PTR(err); 760 return ERR_PTR(err);
640} 761}
641 762
763static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
764{
765 struct in_device *in_dev = ifa->ifa_dev;
766 struct in_ifaddr *ifa1, **ifap;
767
768 if (!ifa->ifa_local)
769 return NULL;
770
771 for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
772 ifap = &ifa1->ifa_next) {
773 if (ifa1->ifa_mask == ifa->ifa_mask &&
774 inet_ifa_match(ifa1->ifa_address, ifa) &&
775 ifa1->ifa_local == ifa->ifa_local)
776 return ifa1;
777 }
778 return NULL;
779}
780
642static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) 781static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
643{ 782{
644 struct net *net = sock_net(skb->sk); 783 struct net *net = sock_net(skb->sk);
645 struct in_ifaddr *ifa; 784 struct in_ifaddr *ifa;
785 struct in_ifaddr *ifa_existing;
786 __u32 valid_lft = INFINITY_LIFE_TIME;
787 __u32 prefered_lft = INFINITY_LIFE_TIME;
646 788
647 ASSERT_RTNL(); 789 ASSERT_RTNL();
648 790
649 ifa = rtm_to_ifaddr(net, nlh); 791 ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft);
650 if (IS_ERR(ifa)) 792 if (IS_ERR(ifa))
651 return PTR_ERR(ifa); 793 return PTR_ERR(ifa);
652 794
653 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid); 795 ifa_existing = find_matching_ifa(ifa);
796 if (!ifa_existing) {
797 /* It would be best to check for !NLM_F_CREATE here but
798 * userspace alreay relies on not having to provide this.
799 */
800 set_ifa_lifetime(ifa, valid_lft, prefered_lft);
801 return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
802 } else {
803 inet_free_ifa(ifa);
804
805 if (nlh->nlmsg_flags & NLM_F_EXCL ||
806 !(nlh->nlmsg_flags & NLM_F_REPLACE))
807 return -EEXIST;
808
809 set_ifa_lifetime(ifa_existing, valid_lft, prefered_lft);
810 }
811 return 0;
654} 812}
655 813
656/* 814/*
@@ -852,6 +1010,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
852 ifa->ifa_prefixlen = 32; 1010 ifa->ifa_prefixlen = 32;
853 ifa->ifa_mask = inet_make_mask(32); 1011 ifa->ifa_mask = inet_make_mask(32);
854 } 1012 }
1013 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
855 ret = inet_set_ifa(dev, ifa); 1014 ret = inet_set_ifa(dev, ifa);
856 break; 1015 break;
857 1016
@@ -1190,6 +1349,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
1190 ifa->ifa_dev = in_dev; 1349 ifa->ifa_dev = in_dev;
1191 ifa->ifa_scope = RT_SCOPE_HOST; 1350 ifa->ifa_scope = RT_SCOPE_HOST;
1192 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); 1351 memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
1352 set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
1353 INFINITY_LIFE_TIME);
1193 inet_insert_ifa(ifa); 1354 inet_insert_ifa(ifa);
1194 } 1355 }
1195 } 1356 }
@@ -1246,11 +1407,30 @@ static size_t inet_nlmsg_size(void)
1246 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */ 1407 + nla_total_size(IFNAMSIZ); /* IFA_LABEL */
1247} 1408}
1248 1409
1410static inline u32 cstamp_delta(unsigned long cstamp)
1411{
1412 return (cstamp - INITIAL_JIFFIES) * 100UL / HZ;
1413}
1414
1415static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
1416 unsigned long tstamp, u32 preferred, u32 valid)
1417{
1418 struct ifa_cacheinfo ci;
1419
1420 ci.cstamp = cstamp_delta(cstamp);
1421 ci.tstamp = cstamp_delta(tstamp);
1422 ci.ifa_prefered = preferred;
1423 ci.ifa_valid = valid;
1424
1425 return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci);
1426}
1427
1249static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, 1428static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
1250 u32 portid, u32 seq, int event, unsigned int flags) 1429 u32 portid, u32 seq, int event, unsigned int flags)
1251{ 1430{
1252 struct ifaddrmsg *ifm; 1431 struct ifaddrmsg *ifm;
1253 struct nlmsghdr *nlh; 1432 struct nlmsghdr *nlh;
1433 u32 preferred, valid;
1254 1434
1255 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags); 1435 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
1256 if (nlh == NULL) 1436 if (nlh == NULL)
@@ -1259,10 +1439,31 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
1259 ifm = nlmsg_data(nlh); 1439 ifm = nlmsg_data(nlh);
1260 ifm->ifa_family = AF_INET; 1440 ifm->ifa_family = AF_INET;
1261 ifm->ifa_prefixlen = ifa->ifa_prefixlen; 1441 ifm->ifa_prefixlen = ifa->ifa_prefixlen;
1262 ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT; 1442 ifm->ifa_flags = ifa->ifa_flags;
1263 ifm->ifa_scope = ifa->ifa_scope; 1443 ifm->ifa_scope = ifa->ifa_scope;
1264 ifm->ifa_index = ifa->ifa_dev->dev->ifindex; 1444 ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
1265 1445
1446 if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
1447 preferred = ifa->ifa_preferred_lft;
1448 valid = ifa->ifa_valid_lft;
1449 if (preferred != INFINITY_LIFE_TIME) {
1450 long tval = (jiffies - ifa->ifa_tstamp) / HZ;
1451
1452 if (preferred > tval)
1453 preferred -= tval;
1454 else
1455 preferred = 0;
1456 if (valid != INFINITY_LIFE_TIME) {
1457 if (valid > tval)
1458 valid -= tval;
1459 else
1460 valid = 0;
1461 }
1462 }
1463 } else {
1464 preferred = INFINITY_LIFE_TIME;
1465 valid = INFINITY_LIFE_TIME;
1466 }
1266 if ((ifa->ifa_address && 1467 if ((ifa->ifa_address &&
1267 nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) || 1468 nla_put_be32(skb, IFA_ADDRESS, ifa->ifa_address)) ||
1268 (ifa->ifa_local && 1469 (ifa->ifa_local &&
@@ -1270,7 +1471,9 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
1270 (ifa->ifa_broadcast && 1471 (ifa->ifa_broadcast &&
1271 nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) || 1472 nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
1272 (ifa->ifa_label[0] && 1473 (ifa->ifa_label[0] &&
1273 nla_put_string(skb, IFA_LABEL, ifa->ifa_label))) 1474 nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
1475 put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
1476 preferred, valid))
1274 goto nla_put_failure; 1477 goto nla_put_failure;
1275 1478
1276 return nlmsg_end(skb, nlh); 1479 return nlmsg_end(skb, nlh);
@@ -1988,6 +2191,8 @@ void __init devinet_init(void)
1988 register_gifconf(PF_INET, inet_gifconf); 2191 register_gifconf(PF_INET, inet_gifconf);
1989 register_netdevice_notifier(&ip_netdev_notifier); 2192 register_netdevice_notifier(&ip_netdev_notifier);
1990 2193
2194 schedule_delayed_work(&check_lifetime_work, 0);
2195
1991 rtnl_af_register(&inet_af_ops); 2196 rtnl_af_register(&inet_af_ops);
1992 2197
1993 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL); 2198 rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL);