aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
authorAndy Gospodarek <gospo@cumulusnetworks.com>2015-06-23 13:45:36 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-24 05:15:54 -0400
commit8a3d03166f19329b46c6f9e900f93a89f446077b (patch)
tree22daa91207335df8bb3f2081c85d772b037d962a /net/ipv4/fib_semantics.c
parent5c8079d049c8452aeacec96a260200d468afc87d (diff)
net: track link-status of ipv4 nexthops
Add a fib flag called RTNH_F_LINKDOWN to any ipv4 nexthops that are reachable via an interface where carrier is off. No action is taken, but additional flags are passed to userspace to indicate carrier status. This also includes a cleanup to fib_disable_ip to more clearly indicate what event made the function call to replace the more cryptic force option previously used. v2: Split out kernel functionality into 2 patches, this patch simply sets and clears new nexthop flag RTNH_F_LINKDOWN. v3: Cleanups suggested by Alex as well as a bug noticed in fib_sync_down_dev and fib_sync_up when multipath was not enabled. v5: Whitespace and variable declaration fixups suggested by Dave. v6: Style fixups noticed by Dave; ran checkpatch to be sure I got them all. Signed-off-by: Andy Gospodarek <gospo@cumulusnetworks.com> Signed-off-by: Dinesh Dutt <ddutt@cumulusnetworks.com> Acked-by: Scott Feldman <sfeldma@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r--net/ipv4/fib_semantics.c60
1 files changed, 47 insertions, 13 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 28ec3c1823bf..b1b305b1e340 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -266,7 +266,7 @@ static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
266#ifdef CONFIG_IP_ROUTE_CLASSID 266#ifdef CONFIG_IP_ROUTE_CLASSID
267 nh->nh_tclassid != onh->nh_tclassid || 267 nh->nh_tclassid != onh->nh_tclassid ||
268#endif 268#endif
269 ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_F_DEAD)) 269 ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_COMPARE_MASK))
270 return -1; 270 return -1;
271 onh++; 271 onh++;
272 } endfor_nexthops(fi); 272 } endfor_nexthops(fi);
@@ -318,7 +318,7 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
318 nfi->fib_type == fi->fib_type && 318 nfi->fib_type == fi->fib_type &&
319 memcmp(nfi->fib_metrics, fi->fib_metrics, 319 memcmp(nfi->fib_metrics, fi->fib_metrics,
320 sizeof(u32) * RTAX_MAX) == 0 && 320 sizeof(u32) * RTAX_MAX) == 0 &&
321 ((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 && 321 !((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_COMPARE_MASK) &&
322 (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0)) 322 (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
323 return fi; 323 return fi;
324 } 324 }
@@ -604,6 +604,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
604 return -ENODEV; 604 return -ENODEV;
605 if (!(dev->flags & IFF_UP)) 605 if (!(dev->flags & IFF_UP))
606 return -ENETDOWN; 606 return -ENETDOWN;
607 if (!netif_carrier_ok(dev))
608 nh->nh_flags |= RTNH_F_LINKDOWN;
607 nh->nh_dev = dev; 609 nh->nh_dev = dev;
608 dev_hold(dev); 610 dev_hold(dev);
609 nh->nh_scope = RT_SCOPE_LINK; 611 nh->nh_scope = RT_SCOPE_LINK;
@@ -636,6 +638,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
636 if (!dev) 638 if (!dev)
637 goto out; 639 goto out;
638 dev_hold(dev); 640 dev_hold(dev);
641 if (!netif_carrier_ok(dev))
642 nh->nh_flags |= RTNH_F_LINKDOWN;
639 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; 643 err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
640 } else { 644 } else {
641 struct in_device *in_dev; 645 struct in_device *in_dev;
@@ -654,6 +658,8 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
654 nh->nh_dev = in_dev->dev; 658 nh->nh_dev = in_dev->dev;
655 dev_hold(nh->nh_dev); 659 dev_hold(nh->nh_dev);
656 nh->nh_scope = RT_SCOPE_HOST; 660 nh->nh_scope = RT_SCOPE_HOST;
661 if (!netif_carrier_ok(nh->nh_dev))
662 nh->nh_flags |= RTNH_F_LINKDOWN;
657 err = 0; 663 err = 0;
658 } 664 }
659out: 665out:
@@ -920,11 +926,17 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
920 if (!nh->nh_dev) 926 if (!nh->nh_dev)
921 goto failure; 927 goto failure;
922 } else { 928 } else {
929 int linkdown = 0;
930
923 change_nexthops(fi) { 931 change_nexthops(fi) {
924 err = fib_check_nh(cfg, fi, nexthop_nh); 932 err = fib_check_nh(cfg, fi, nexthop_nh);
925 if (err != 0) 933 if (err != 0)
926 goto failure; 934 goto failure;
935 if (nexthop_nh->nh_flags & RTNH_F_LINKDOWN)
936 linkdown++;
927 } endfor_nexthops(fi) 937 } endfor_nexthops(fi)
938 if (linkdown == fi->fib_nhs)
939 fi->fib_flags |= RTNH_F_LINKDOWN;
928 } 940 }
929 941
930 if (fi->fib_prefsrc) { 942 if (fi->fib_prefsrc) {
@@ -1103,7 +1115,7 @@ int fib_sync_down_addr(struct net *net, __be32 local)
1103 return ret; 1115 return ret;
1104} 1116}
1105 1117
1106int fib_sync_down_dev(struct net_device *dev, int force) 1118int fib_sync_down_dev(struct net_device *dev, unsigned long event)
1107{ 1119{
1108 int ret = 0; 1120 int ret = 0;
1109 int scope = RT_SCOPE_NOWHERE; 1121 int scope = RT_SCOPE_NOWHERE;
@@ -1112,7 +1124,8 @@ int fib_sync_down_dev(struct net_device *dev, int force)
1112 struct hlist_head *head = &fib_info_devhash[hash]; 1124 struct hlist_head *head = &fib_info_devhash[hash];
1113 struct fib_nh *nh; 1125 struct fib_nh *nh;
1114 1126
1115 if (force) 1127 if (event == NETDEV_UNREGISTER ||
1128 event == NETDEV_DOWN)
1116 scope = -1; 1129 scope = -1;
1117 1130
1118 hlist_for_each_entry(nh, head, nh_hash) { 1131 hlist_for_each_entry(nh, head, nh_hash) {
@@ -1129,7 +1142,15 @@ int fib_sync_down_dev(struct net_device *dev, int force)
1129 dead++; 1142 dead++;
1130 else if (nexthop_nh->nh_dev == dev && 1143 else if (nexthop_nh->nh_dev == dev &&
1131 nexthop_nh->nh_scope != scope) { 1144 nexthop_nh->nh_scope != scope) {
1132 nexthop_nh->nh_flags |= RTNH_F_DEAD; 1145 switch (event) {
1146 case NETDEV_DOWN:
1147 case NETDEV_UNREGISTER:
1148 nexthop_nh->nh_flags |= RTNH_F_DEAD;
1149 /* fall through */
1150 case NETDEV_CHANGE:
1151 nexthop_nh->nh_flags |= RTNH_F_LINKDOWN;
1152 break;
1153 }
1133#ifdef CONFIG_IP_ROUTE_MULTIPATH 1154#ifdef CONFIG_IP_ROUTE_MULTIPATH
1134 spin_lock_bh(&fib_multipath_lock); 1155 spin_lock_bh(&fib_multipath_lock);
1135 fi->fib_power -= nexthop_nh->nh_power; 1156 fi->fib_power -= nexthop_nh->nh_power;
@@ -1139,14 +1160,23 @@ int fib_sync_down_dev(struct net_device *dev, int force)
1139 dead++; 1160 dead++;
1140 } 1161 }
1141#ifdef CONFIG_IP_ROUTE_MULTIPATH 1162#ifdef CONFIG_IP_ROUTE_MULTIPATH
1142 if (force > 1 && nexthop_nh->nh_dev == dev) { 1163 if (event == NETDEV_UNREGISTER &&
1164 nexthop_nh->nh_dev == dev) {
1143 dead = fi->fib_nhs; 1165 dead = fi->fib_nhs;
1144 break; 1166 break;
1145 } 1167 }
1146#endif 1168#endif
1147 } endfor_nexthops(fi) 1169 } endfor_nexthops(fi)
1148 if (dead == fi->fib_nhs) { 1170 if (dead == fi->fib_nhs) {
1149 fi->fib_flags |= RTNH_F_DEAD; 1171 switch (event) {
1172 case NETDEV_DOWN:
1173 case NETDEV_UNREGISTER:
1174 fi->fib_flags |= RTNH_F_DEAD;
1175 /* fall through */
1176 case NETDEV_CHANGE:
1177 fi->fib_flags |= RTNH_F_LINKDOWN;
1178 break;
1179 }
1150 ret++; 1180 ret++;
1151 } 1181 }
1152 } 1182 }
@@ -1210,13 +1240,11 @@ out:
1210 return; 1240 return;
1211} 1241}
1212 1242
1213#ifdef CONFIG_IP_ROUTE_MULTIPATH
1214
1215/* 1243/*
1216 * Dead device goes up. We wake up dead nexthops. 1244 * Dead device goes up. We wake up dead nexthops.
1217 * It takes sense only on multipath routes. 1245 * It takes sense only on multipath routes.
1218 */ 1246 */
1219int fib_sync_up(struct net_device *dev) 1247int fib_sync_up(struct net_device *dev, unsigned int nh_flags)
1220{ 1248{
1221 struct fib_info *prev_fi; 1249 struct fib_info *prev_fi;
1222 unsigned int hash; 1250 unsigned int hash;
@@ -1243,7 +1271,7 @@ int fib_sync_up(struct net_device *dev)
1243 prev_fi = fi; 1271 prev_fi = fi;
1244 alive = 0; 1272 alive = 0;
1245 change_nexthops(fi) { 1273 change_nexthops(fi) {
1246 if (!(nexthop_nh->nh_flags & RTNH_F_DEAD)) { 1274 if (!(nexthop_nh->nh_flags & nh_flags)) {
1247 alive++; 1275 alive++;
1248 continue; 1276 continue;
1249 } 1277 }
@@ -1254,14 +1282,18 @@ int fib_sync_up(struct net_device *dev)
1254 !__in_dev_get_rtnl(dev)) 1282 !__in_dev_get_rtnl(dev))
1255 continue; 1283 continue;
1256 alive++; 1284 alive++;
1285#ifdef CONFIG_IP_ROUTE_MULTIPATH
1257 spin_lock_bh(&fib_multipath_lock); 1286 spin_lock_bh(&fib_multipath_lock);
1258 nexthop_nh->nh_power = 0; 1287 nexthop_nh->nh_power = 0;
1259 nexthop_nh->nh_flags &= ~RTNH_F_DEAD; 1288 nexthop_nh->nh_flags &= ~nh_flags;
1260 spin_unlock_bh(&fib_multipath_lock); 1289 spin_unlock_bh(&fib_multipath_lock);
1290#else
1291 nexthop_nh->nh_flags &= ~nh_flags;
1292#endif
1261 } endfor_nexthops(fi) 1293 } endfor_nexthops(fi)
1262 1294
1263 if (alive > 0) { 1295 if (alive > 0) {
1264 fi->fib_flags &= ~RTNH_F_DEAD; 1296 fi->fib_flags &= ~nh_flags;
1265 ret++; 1297 ret++;
1266 } 1298 }
1267 } 1299 }
@@ -1269,6 +1301,8 @@ int fib_sync_up(struct net_device *dev)
1269 return ret; 1301 return ret;
1270} 1302}
1271 1303
1304#ifdef CONFIG_IP_ROUTE_MULTIPATH
1305
1272/* 1306/*
1273 * The algorithm is suboptimal, but it provides really 1307 * The algorithm is suboptimal, but it provides really
1274 * fair weighted route distribution. 1308 * fair weighted route distribution.