diff options
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 41 |
1 files changed, 30 insertions, 11 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index c7358ea4ae93..3a06586b170c 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -1202,23 +1202,40 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event) | |||
1202 | } | 1202 | } |
1203 | 1203 | ||
1204 | /* Must be invoked inside of an RCU protected region. */ | 1204 | /* Must be invoked inside of an RCU protected region. */ |
1205 | void fib_select_default(struct fib_result *res) | 1205 | void fib_select_default(const struct flowi4 *flp, struct fib_result *res) |
1206 | { | 1206 | { |
1207 | struct fib_info *fi = NULL, *last_resort = NULL; | 1207 | struct fib_info *fi = NULL, *last_resort = NULL; |
1208 | struct hlist_head *fa_head = res->fa_head; | 1208 | struct hlist_head *fa_head = res->fa_head; |
1209 | struct fib_table *tb = res->table; | 1209 | struct fib_table *tb = res->table; |
1210 | u8 slen = 32 - res->prefixlen; | ||
1210 | int order = -1, last_idx = -1; | 1211 | int order = -1, last_idx = -1; |
1211 | struct fib_alias *fa; | 1212 | struct fib_alias *fa, *fa1 = NULL; |
1213 | u32 last_prio = res->fi->fib_priority; | ||
1214 | u8 last_tos = 0; | ||
1212 | 1215 | ||
1213 | hlist_for_each_entry_rcu(fa, fa_head, fa_list) { | 1216 | hlist_for_each_entry_rcu(fa, fa_head, fa_list) { |
1214 | struct fib_info *next_fi = fa->fa_info; | 1217 | struct fib_info *next_fi = fa->fa_info; |
1215 | 1218 | ||
1219 | if (fa->fa_slen != slen) | ||
1220 | continue; | ||
1221 | if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) | ||
1222 | continue; | ||
1223 | if (fa->tb_id != tb->tb_id) | ||
1224 | continue; | ||
1225 | if (next_fi->fib_priority > last_prio && | ||
1226 | fa->fa_tos == last_tos) { | ||
1227 | if (last_tos) | ||
1228 | continue; | ||
1229 | break; | ||
1230 | } | ||
1231 | if (next_fi->fib_flags & RTNH_F_DEAD) | ||
1232 | continue; | ||
1233 | last_tos = fa->fa_tos; | ||
1234 | last_prio = next_fi->fib_priority; | ||
1235 | |||
1216 | if (next_fi->fib_scope != res->scope || | 1236 | if (next_fi->fib_scope != res->scope || |
1217 | fa->fa_type != RTN_UNICAST) | 1237 | fa->fa_type != RTN_UNICAST) |
1218 | continue; | 1238 | continue; |
1219 | |||
1220 | if (next_fi->fib_priority > res->fi->fib_priority) | ||
1221 | break; | ||
1222 | if (!next_fi->fib_nh[0].nh_gw || | 1239 | if (!next_fi->fib_nh[0].nh_gw || |
1223 | next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) | 1240 | next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) |
1224 | continue; | 1241 | continue; |
@@ -1228,10 +1245,11 @@ void fib_select_default(struct fib_result *res) | |||
1228 | if (!fi) { | 1245 | if (!fi) { |
1229 | if (next_fi != res->fi) | 1246 | if (next_fi != res->fi) |
1230 | break; | 1247 | break; |
1248 | fa1 = fa; | ||
1231 | } else if (!fib_detect_death(fi, order, &last_resort, | 1249 | } else if (!fib_detect_death(fi, order, &last_resort, |
1232 | &last_idx, tb->tb_default)) { | 1250 | &last_idx, fa1->fa_default)) { |
1233 | fib_result_assign(res, fi); | 1251 | fib_result_assign(res, fi); |
1234 | tb->tb_default = order; | 1252 | fa1->fa_default = order; |
1235 | goto out; | 1253 | goto out; |
1236 | } | 1254 | } |
1237 | fi = next_fi; | 1255 | fi = next_fi; |
@@ -1239,20 +1257,21 @@ void fib_select_default(struct fib_result *res) | |||
1239 | } | 1257 | } |
1240 | 1258 | ||
1241 | if (order <= 0 || !fi) { | 1259 | if (order <= 0 || !fi) { |
1242 | tb->tb_default = -1; | 1260 | if (fa1) |
1261 | fa1->fa_default = -1; | ||
1243 | goto out; | 1262 | goto out; |
1244 | } | 1263 | } |
1245 | 1264 | ||
1246 | if (!fib_detect_death(fi, order, &last_resort, &last_idx, | 1265 | if (!fib_detect_death(fi, order, &last_resort, &last_idx, |
1247 | tb->tb_default)) { | 1266 | fa1->fa_default)) { |
1248 | fib_result_assign(res, fi); | 1267 | fib_result_assign(res, fi); |
1249 | tb->tb_default = order; | 1268 | fa1->fa_default = order; |
1250 | goto out; | 1269 | goto out; |
1251 | } | 1270 | } |
1252 | 1271 | ||
1253 | if (last_idx >= 0) | 1272 | if (last_idx >= 0) |
1254 | fib_result_assign(res, last_resort); | 1273 | fib_result_assign(res, last_resort); |
1255 | tb->tb_default = last_idx; | 1274 | fa1->fa_default = last_idx; |
1256 | out: | 1275 | out: |
1257 | return; | 1276 | return; |
1258 | } | 1277 | } |