diff options
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 1bf6fb906cfc..b15857d2b77e 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -1136,6 +1136,62 @@ int fib_sync_down_dev(struct net_device *dev, int force) | |||
1136 | return ret; | 1136 | return ret; |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | /* Must be invoked inside of an RCU protected region. */ | ||
1140 | void fib_select_default(struct fib_result *res) | ||
1141 | { | ||
1142 | struct fib_info *fi = NULL, *last_resort = NULL; | ||
1143 | struct list_head *fa_head = res->fa_head; | ||
1144 | struct fib_table *tb = res->table; | ||
1145 | int order = -1, last_idx = -1; | ||
1146 | struct fib_alias *fa; | ||
1147 | |||
1148 | list_for_each_entry_rcu(fa, fa_head, fa_list) { | ||
1149 | struct fib_info *next_fi = fa->fa_info; | ||
1150 | |||
1151 | if (fa->fa_scope != res->scope || | ||
1152 | fa->fa_type != RTN_UNICAST) | ||
1153 | continue; | ||
1154 | |||
1155 | if (next_fi->fib_priority > res->fi->fib_priority) | ||
1156 | break; | ||
1157 | if (!next_fi->fib_nh[0].nh_gw || | ||
1158 | next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) | ||
1159 | continue; | ||
1160 | |||
1161 | fib_alias_accessed(fa); | ||
1162 | |||
1163 | if (fi == NULL) { | ||
1164 | if (next_fi != res->fi) | ||
1165 | break; | ||
1166 | } else if (!fib_detect_death(fi, order, &last_resort, | ||
1167 | &last_idx, tb->tb_default)) { | ||
1168 | fib_result_assign(res, fi); | ||
1169 | tb->tb_default = order; | ||
1170 | goto out; | ||
1171 | } | ||
1172 | fi = next_fi; | ||
1173 | order++; | ||
1174 | } | ||
1175 | |||
1176 | if (order <= 0 || fi == NULL) { | ||
1177 | tb->tb_default = -1; | ||
1178 | goto out; | ||
1179 | } | ||
1180 | |||
1181 | if (!fib_detect_death(fi, order, &last_resort, &last_idx, | ||
1182 | tb->tb_default)) { | ||
1183 | fib_result_assign(res, fi); | ||
1184 | tb->tb_default = order; | ||
1185 | goto out; | ||
1186 | } | ||
1187 | |||
1188 | if (last_idx >= 0) | ||
1189 | fib_result_assign(res, last_resort); | ||
1190 | tb->tb_default = last_idx; | ||
1191 | out: | ||
1192 | rcu_read_unlock(); | ||
1193 | } | ||
1194 | |||
1139 | #ifdef CONFIG_IP_ROUTE_MULTIPATH | 1195 | #ifdef CONFIG_IP_ROUTE_MULTIPATH |
1140 | 1196 | ||
1141 | /* | 1197 | /* |