aboutsummaryrefslogtreecommitdiffstats
path: root/include/net/ip_mp_alg.h
blob: beffdd66ad74f81ac2c5a9d40003ff4ad372102f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/* ip_mp_alg.h: IPV4 multipath algorithm support.
 *
 * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
 * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
 */

#ifndef _NET_IP_MP_ALG_H
#define _NET_IP_MP_ALG_H

#include <linux/ip_mp_alg.h>
#include <net/flow.h>
#include <net/route.h>

struct fib_nh;

struct ip_mp_alg_ops {
	void	(*mp_alg_select_route)(const struct flowi *flp,
				       struct rtable *rth, struct rtable **rp);
	void	(*mp_alg_flush)(void);
	void	(*mp_alg_set_nhinfo)(__be32 network, __be32 netmask,
				     unsigned char prefixlen,
				     const struct fib_nh *nh);
	void	(*mp_alg_remove)(struct rtable *rth);
};

extern int multipath_alg_register(struct ip_mp_alg_ops *, enum ip_mp_alg);
extern void multipath_alg_unregister(struct ip_mp_alg_ops *, enum ip_mp_alg);

extern struct ip_mp_alg_ops *ip_mp_alg_table[];

static inline int multipath_select_route(const struct flowi *flp,
					 struct rtable *rth,
					 struct rtable **rp)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
	struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];

	/* mp_alg_select_route _MUST_ be implemented */
	if (ops && (rth->u.dst.flags & DST_BALANCED)) {
		ops->mp_alg_select_route(flp, rth, rp);
		return 1;
	}
#endif
	return 0;
}

static inline void multipath_flush(void)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
	int i;

	for (i = IP_MP_ALG_NONE; i <= IP_MP_ALG_MAX; i++) {
		struct ip_mp_alg_ops *ops = ip_mp_alg_table[i];

		if (ops && ops->mp_alg_flush)
			ops->mp_alg_flush();
	}
#endif
}

static inline void multipath_set_nhinfo(struct rtable *rth,
					__be32 network, __be32 netmask,
					unsigned char prefixlen,
					const struct fib_nh *nh)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
	struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];

	if (ops && ops->mp_alg_set_nhinfo)
		ops->mp_alg_set_nhinfo(network, netmask, prefixlen, nh);
#endif
}

static inline void multipath_remove(struct rtable *rth)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
	struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];

	if (ops && ops->mp_alg_remove &&
	    (rth->u.dst.flags & DST_BALANCED))
		ops->mp_alg_remove(rth);
#endif
}

static inline int multipath_comparekeys(const struct flowi *flp1,
					const struct flowi *flp2)
{
	return flp1->fl4_dst == flp2->fl4_dst &&
		flp1->fl4_src == flp2->fl4_src &&
		flp1->oif == flp2->oif &&
#ifdef CONFIG_IP_ROUTE_FWMARK
		flp1->fl4_fwmark == flp2->fl4_fwmark &&
#endif
		!((flp1->fl4_tos ^ flp2->fl4_tos) &
		  (IPTOS_RT_MASK | RTO_ONLINK));
}

#endif /* _NET_IP_MP_ALG_H */