mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 08:58:07 +00:00
2392debc2b
fib_select_default considers alternative routes only when res->fi is for the first alias in res->fa_head. In the common case this can happen only when the initial lookup matches the first alias with highest TOS value. This prevents the alternative routes to require specific TOS. This patch solves the problem as follows: - routes that require specific TOS should be returned by fib_select_default only when TOS matches, as already done in fib_table_lookup. This rule implies that depending on the TOS we can have many different lists of alternative gateways and we have to keep the last used gateway (fa_default) in first alias for the TOS instead of using single tb_default value. - as the aliases are ordered by many keys (TOS desc, fib_priority asc), we restrict the possible results to routes with matching TOS and lowest metric (fib_priority) and routes that match any TOS, again with lowest metric. For example, packet with TOS 8 can not use gw3 (not lowest metric), gw4 (different TOS) and gw6 (not lowest metric), all other gateways can be used: tos 8 via gw1 metric 2 <--- res->fa_head and res->fi tos 8 via gw2 metric 2 tos 8 via gw3 metric 3 tos 4 via gw4 tos 0 via gw5 tos 0 via gw6 metric 1 Reported-by: Hagen Paul Pfeifer <hagen@jauu.net> Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: David S. Miller <davem@davemloft.net>
53 lines
1.3 KiB
C
53 lines
1.3 KiB
C
#ifndef _FIB_LOOKUP_H
|
|
#define _FIB_LOOKUP_H
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/list.h>
|
|
#include <net/ip_fib.h>
|
|
|
|
struct fib_alias {
|
|
struct hlist_node fa_list;
|
|
struct fib_info *fa_info;
|
|
u8 fa_tos;
|
|
u8 fa_type;
|
|
u8 fa_state;
|
|
u8 fa_slen;
|
|
u32 tb_id;
|
|
s16 fa_default;
|
|
struct rcu_head rcu;
|
|
};
|
|
|
|
#define FA_S_ACCESSED 0x01
|
|
|
|
/* Dont write on fa_state unless needed, to keep it shared on all cpus */
|
|
static inline void fib_alias_accessed(struct fib_alias *fa)
|
|
{
|
|
if (!(fa->fa_state & FA_S_ACCESSED))
|
|
fa->fa_state |= FA_S_ACCESSED;
|
|
}
|
|
|
|
/* Exported by fib_semantics.c */
|
|
void fib_release_info(struct fib_info *);
|
|
struct fib_info *fib_create_info(struct fib_config *cfg);
|
|
int fib_nh_match(struct fib_config *cfg, struct fib_info *fi);
|
|
int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id,
|
|
u8 type, __be32 dst, int dst_len, u8 tos, struct fib_info *fi,
|
|
unsigned int);
|
|
void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len,
|
|
u32 tb_id, const struct nl_info *info, unsigned int nlm_flags);
|
|
|
|
static inline void fib_result_assign(struct fib_result *res,
|
|
struct fib_info *fi)
|
|
{
|
|
/* we used to play games with refcounts, but we now use RCU */
|
|
res->fi = fi;
|
|
}
|
|
|
|
struct fib_prop {
|
|
int error;
|
|
u8 scope;
|
|
};
|
|
|
|
extern const struct fib_prop fib_props[RTN_MAX + 1];
|
|
|
|
#endif /* _FIB_LOOKUP_H */
|