Commit dcddf5b0 authored by David S. Miller's avatar David S. Miller

[IPV4]: Use generic struct flowi as routing key.

parent 3f43be64
/* /*
* *
* Flow based forwarding rules (usage: firewalling, etc) * Generic internet FLOW.
* *
*/ */
...@@ -8,12 +8,16 @@ ...@@ -8,12 +8,16 @@
#define _NET_FLOW_H #define _NET_FLOW_H
struct flowi { struct flowi {
int proto; /* {TCP, UDP, ICMP} */ int oif;
int iif;
union { union {
struct { struct {
__u32 daddr; __u32 daddr;
__u32 saddr; __u32 saddr;
__u32 fwmark;
__u8 tos;
__u8 scope;
} ip4_u; } ip4_u;
struct { struct {
...@@ -27,9 +31,12 @@ struct flowi { ...@@ -27,9 +31,12 @@ struct flowi {
#define fl6_flowlabel nl_u.ip6_u.flowlabel #define fl6_flowlabel nl_u.ip6_u.flowlabel
#define fl4_dst nl_u.ip4_u.daddr #define fl4_dst nl_u.ip4_u.daddr
#define fl4_src nl_u.ip4_u.saddr #define fl4_src nl_u.ip4_u.saddr
#define fl4_fwmark nl_u.ip4_u.fwmark
#define fl4_tos nl_u.ip4_u.tos
#define fl4_scope nl_u.ip4_u.scope
int oif; __u8 proto;
__u8 flags;
union { union {
struct { struct {
__u16 sport; __u16 sport;
...@@ -41,61 +48,8 @@ struct flowi { ...@@ -41,61 +48,8 @@ struct flowi {
__u8 code; __u8 code;
} icmpt; } icmpt;
unsigned long data; __u32 spi;
} uli_u; } uli_u;
}; };
#define FLOWR_NODECISION 0 /* rule not appliable to flow */
#define FLOWR_SELECT 1 /* flow must follow this rule */
#define FLOWR_CLEAR 2 /* priority level clears flow */
#define FLOWR_ERROR 3
struct fl_acc_args {
int type;
#define FL_ARG_FORWARD 1
#define FL_ARG_ORIGIN 2
union {
struct sk_buff *skb;
struct {
struct sock *sk;
struct flowi *flow;
} fl_o;
} fl_u;
};
struct pkt_filter {
atomic_t refcnt;
unsigned int offset;
__u32 value;
__u32 mask;
struct pkt_filter *next;
};
#define FLR_INPUT 1
#define FLR_OUTPUT 2
struct flow_filter {
int type;
union {
struct pkt_filter *filter;
struct sock *sk;
} u;
};
struct flow_rule {
struct flow_rule_ops *ops;
unsigned char private[0];
};
struct flow_rule_ops {
int (*accept)(struct rt6_info *rt,
struct rt6_info *rule,
struct fl_acc_args *args,
struct rt6_info **nrt);
};
#endif #endif
...@@ -70,14 +70,6 @@ struct rt6_info ...@@ -70,14 +70,6 @@ struct rt6_info
u8 rt6i_hoplimit; u8 rt6i_hoplimit;
atomic_t rt6i_ref; atomic_t rt6i_ref;
union {
struct flow_rule *rt6iu_flowr;
struct flow_filter *rt6iu_filter;
} flow_u;
#define rt6i_flowr flow_u.rt6iu_flowr
#define rt6i_filter flow_u.rt6iu_filter
struct rt6key rt6i_dst; struct rt6key rt6i_dst;
struct rt6key rt6i_src; struct rt6key rt6i_src;
}; };
......
#ifndef __NET_IP6_FW_H
#define __NET_IP6_FW_H
#define IP6_FW_LISTHEAD 0x1000
#define IP6_FW_ACCEPT 0x0001
#define IP6_FW_REJECT 0x0002
#define IP6_FW_DEBUG 2
#define IP6_FW_MSG_ADD 1
#define IP6_FW_MSG_DEL 2
#define IP6_FW_MSG_REPORT 3
/*
* Fast "hack" user interface
*/
struct ip6_fw_msg {
struct in6_addr dst;
struct in6_addr src;
int dst_len;
int src_len;
int action;
int policy;
int proto;
union {
struct {
__u16 sport;
__u16 dport;
} transp;
unsigned long data;
int icmp_type;
} u;
int msg_len;
};
#ifdef __KERNEL__
#include <net/flow.h>
struct ip6_fw_rule {
struct flow_rule flowr;
struct ip6_fw_rule *next;
struct ip6_fw_rule *prev;
struct flowi info;
unsigned long policy;
};
#endif
#endif
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#define _NET_IP_FIB_H #define _NET_IP_FIB_H
#include <linux/config.h> #include <linux/config.h>
#include <net/flow.h>
struct kern_rta struct kern_rta
{ {
...@@ -117,7 +118,7 @@ struct fib_table ...@@ -117,7 +118,7 @@ struct fib_table
{ {
unsigned char tb_id; unsigned char tb_id;
unsigned tb_stamp; unsigned tb_stamp;
int (*tb_lookup)(struct fib_table *tb, const struct rt_key *key, struct fib_result *res); int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
int (*tb_insert)(struct fib_table *table, struct rtmsg *r, int (*tb_insert)(struct fib_table *table, struct rtmsg *r,
struct kern_rta *rta, struct nlmsghdr *n, struct kern_rta *rta, struct nlmsghdr *n,
struct netlink_skb_parms *req); struct netlink_skb_parms *req);
...@@ -130,7 +131,7 @@ struct fib_table ...@@ -130,7 +131,7 @@ struct fib_table
int (*tb_get_info)(struct fib_table *table, char *buf, int (*tb_get_info)(struct fib_table *table, char *buf,
int first, int count); int first, int count);
void (*tb_select_default)(struct fib_table *table, void (*tb_select_default)(struct fib_table *table,
const struct rt_key *key, struct fib_result *res); const struct flowi *flp, struct fib_result *res);
unsigned char tb_data[0]; unsigned char tb_data[0];
}; };
...@@ -152,18 +153,18 @@ static inline struct fib_table *fib_new_table(int id) ...@@ -152,18 +153,18 @@ static inline struct fib_table *fib_new_table(int id)
return fib_get_table(id); return fib_get_table(id);
} }
static inline int fib_lookup(const struct rt_key *key, struct fib_result *res) static inline int fib_lookup(const struct flowi *flp, struct fib_result *res)
{ {
if (local_table->tb_lookup(local_table, key, res) && if (local_table->tb_lookup(local_table, flp, res) &&
main_table->tb_lookup(main_table, key, res)) main_table->tb_lookup(main_table, flp, res))
return -ENETUNREACH; return -ENETUNREACH;
return 0; return 0;
} }
static inline void fib_select_default(const struct rt_key *key, struct fib_result *res) static inline void fib_select_default(const struct flowi *flp, struct fib_result *res)
{ {
if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
main_table->tb_select_default(main_table, key, res); main_table->tb_select_default(main_table, flp, res);
} }
#else /* CONFIG_IP_MULTIPLE_TABLES */ #else /* CONFIG_IP_MULTIPLE_TABLES */
...@@ -171,7 +172,7 @@ static inline void fib_select_default(const struct rt_key *key, struct fib_resul ...@@ -171,7 +172,7 @@ static inline void fib_select_default(const struct rt_key *key, struct fib_resul
#define main_table (fib_tables[RT_TABLE_MAIN]) #define main_table (fib_tables[RT_TABLE_MAIN])
extern struct fib_table * fib_tables[RT_TABLE_MAX+1]; extern struct fib_table * fib_tables[RT_TABLE_MAX+1];
extern int fib_lookup(const struct rt_key *key, struct fib_result *res); extern int fib_lookup(const struct flowi *flp, struct fib_result *res);
extern struct fib_table *__fib_new_table(int id); extern struct fib_table *__fib_new_table(int id);
extern void fib_rule_put(struct fib_rule *r); extern void fib_rule_put(struct fib_rule *r);
...@@ -191,7 +192,7 @@ static inline struct fib_table *fib_new_table(int id) ...@@ -191,7 +192,7 @@ static inline struct fib_table *fib_new_table(int id)
return fib_tables[id] ? : __fib_new_table(id); return fib_tables[id] ? : __fib_new_table(id);
} }
extern void fib_select_default(const struct rt_key *key, struct fib_result *res); extern void fib_select_default(const struct flowi *flp, struct fib_result *res);
#endif /* CONFIG_IP_MULTIPLE_TABLES */ #endif /* CONFIG_IP_MULTIPLE_TABLES */
...@@ -204,13 +205,13 @@ extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *ar ...@@ -204,13 +205,13 @@ extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *ar
extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb); extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
struct net_device *dev, u32 *spec_dst, u32 *itag); struct net_device *dev, u32 *spec_dst, u32 *itag);
extern void fib_select_multipath(const struct rt_key *key, struct fib_result *res); extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
/* Exported by fib_semantics.c */ /* Exported by fib_semantics.c */
extern int ip_fib_check_default(u32 gw, struct net_device *dev); extern int ip_fib_check_default(u32 gw, struct net_device *dev);
extern void fib_release_info(struct fib_info *); extern void fib_release_info(struct fib_info *);
extern int fib_semantic_match(int type, struct fib_info *, extern int fib_semantic_match(int type, struct fib_info *,
const struct rt_key *, struct fib_result*); const struct flowi *, struct fib_result*);
extern struct fib_info *fib_create_info(const struct rtmsg *r, struct kern_rta *rta, extern struct fib_info *fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
const struct nlmsghdr *, int *err); const struct nlmsghdr *, int *err);
extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *, struct kern_rta *rta, struct fib_info *fi); extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *, struct kern_rta *rta, struct fib_info *fi);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <net/dst.h> #include <net/dst.h>
#include <net/inetpeer.h> #include <net/inetpeer.h>
#include <net/flow.h>
#include <linux/in_route.h> #include <linux/in_route.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/route.h> #include <linux/route.h>
...@@ -45,19 +46,6 @@ ...@@ -45,19 +46,6 @@
#define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sk->localroute) #define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sk->localroute)
struct rt_key
{
__u32 dst;
__u32 src;
int iif;
int oif;
#ifdef CONFIG_IP_ROUTE_FWMARK
__u32 fwmark;
#endif
__u8 tos;
__u8 scope;
};
struct inet_peer; struct inet_peer;
struct rtable struct rtable
{ {
...@@ -78,7 +66,7 @@ struct rtable ...@@ -78,7 +66,7 @@ struct rtable
__u32 rt_gateway; __u32 rt_gateway;
/* Cache lookup keys */ /* Cache lookup keys */
struct rt_key key; struct flowi fl;
/* Miscellaneous cached information */ /* Miscellaneous cached information */
__u32 rt_spec_dst; /* RFC1122 specific destination */ __u32 rt_spec_dst; /* RFC1122 specific destination */
...@@ -124,7 +112,7 @@ extern void ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw, ...@@ -124,7 +112,7 @@ extern void ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw,
u32 src, u8 tos, struct net_device *dev); u32 src, u8 tos, struct net_device *dev);
extern void ip_rt_advice(struct rtable **rp, int advice); extern void ip_rt_advice(struct rtable **rp, int advice);
extern void rt_cache_flush(int how); extern void rt_cache_flush(int how);
extern int ip_route_output_key(struct rtable **, const struct rt_key *key); extern int ip_route_output_key(struct rtable **, const struct flowi *flp);
extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin); extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu); extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu); extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
...@@ -136,16 +124,6 @@ extern int ip_rt_ioctl(unsigned int cmd, void *arg); ...@@ -136,16 +124,6 @@ extern int ip_rt_ioctl(unsigned int cmd, void *arg);
extern void ip_rt_get_source(u8 *src, struct rtable *rt); extern void ip_rt_get_source(u8 *src, struct rtable *rt);
extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb); extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb);
/* Deprecated: use ip_route_output_key directly */
static inline int ip_route_output(struct rtable **rp,
u32 daddr, u32 saddr, u32 tos, int oif)
{
struct rt_key key = { dst:daddr, src:saddr, oif:oif, tos:tos };
return ip_route_output_key(rp, &key);
}
static inline void ip_rt_put(struct rtable * rt) static inline void ip_rt_put(struct rtable * rt)
{ {
if (rt) if (rt)
...@@ -163,15 +141,20 @@ static inline char rt_tos2priority(u8 tos) ...@@ -163,15 +141,20 @@ static inline char rt_tos2priority(u8 tos)
static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif) static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif)
{ {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
.saddr = src,
.tos = tos } },
.oif = oif };
int err; int err;
err = ip_route_output(rp, dst, src, tos, oif); err = ip_route_output_key(rp, &fl);
if (err || (dst && src)) if (err || (dst && src))
return err; return err;
dst = (*rp)->rt_dst; fl.fl4_dst = (*rp)->rt_dst;
src = (*rp)->rt_src; fl.fl4_src = (*rp)->rt_src;
ip_rt_put(*rp); ip_rt_put(*rp);
*rp = NULL; *rp = NULL;
return ip_route_output(rp, dst, src, tos, oif); return ip_route_output_key(rp, &fl);
} }
extern void rt_bind_peer(struct rtable *rt, int create); extern void rt_bind_peer(struct rtable *rt, int create);
......
...@@ -509,6 +509,7 @@ int clip_setentry(struct atm_vcc *vcc,u32 ip) ...@@ -509,6 +509,7 @@ int clip_setentry(struct atm_vcc *vcc,u32 ip)
struct atmarp_entry *entry; struct atmarp_entry *entry;
int error; int error;
struct clip_vcc *clip_vcc; struct clip_vcc *clip_vcc;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = 1 } } };
struct rtable *rt; struct rtable *rt;
if (vcc->push != clip_push) { if (vcc->push != clip_push) {
...@@ -525,7 +526,7 @@ int clip_setentry(struct atm_vcc *vcc,u32 ip) ...@@ -525,7 +526,7 @@ int clip_setentry(struct atm_vcc *vcc,u32 ip)
unlink_clip_vcc(clip_vcc); unlink_clip_vcc(clip_vcc);
return 0; return 0;
} }
error = ip_route_output(&rt,ip,0,1,0); error = ip_route_output_key(&rt,&fl);
if (error) return error; if (error) return error;
neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1); neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1);
ip_rt_put(rt); ip_rt_put(rt);
......
...@@ -563,13 +563,15 @@ int ip_route_me_harder(struct sk_buff **pskb) ...@@ -563,13 +563,15 @@ int ip_route_me_harder(struct sk_buff **pskb)
{ {
struct iphdr *iph = (*pskb)->nh.iph; struct iphdr *iph = (*pskb)->nh.iph;
struct rtable *rt; struct rtable *rt;
struct rt_key key = { dst:iph->daddr, struct flowi fl = { .nl_u = { .ip4_u =
src:iph->saddr, { .daddr = iph->daddr,
oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, .saddr = iph->saddr,
tos:RT_TOS(iph->tos)|RTO_CONN, .tos = RT_TOS(iph->tos)|RTO_CONN,
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
fwmark:(*pskb)->nfmark .fwmark = (*pskb)->nfmark
#endif #endif
} },
.oif = (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
}; };
struct net_device *dev_src = NULL; struct net_device *dev_src = NULL;
int err; int err;
...@@ -578,10 +580,10 @@ int ip_route_me_harder(struct sk_buff **pskb) ...@@ -578,10 +580,10 @@ int ip_route_me_harder(struct sk_buff **pskb)
0 or a local address; however some non-standard hacks like 0 or a local address; however some non-standard hacks like
ipt_REJECT.c:send_reset() can cause packets with foreign ipt_REJECT.c:send_reset() can cause packets with foreign
saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */ saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */
if(key.src && !(dev_src = ip_dev_find(key.src))) if(fl.fl4_src && !(dev_src = ip_dev_find(fl.fl4_src)))
key.src = 0; fl.fl4_src = 0;
if ((err=ip_route_output_key(&rt, &key)) != 0) { if ((err=ip_route_output_key(&rt, &fl)) != 0) {
printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n", printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n",
NIPQUAD(iph->daddr), NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), NIPQUAD(iph->saddr),
(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
......
...@@ -347,11 +347,13 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) ...@@ -347,11 +347,13 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev) static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
{ {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip,
.saddr = tip } } };
struct rtable *rt; struct rtable *rt;
int flag = 0; int flag = 0;
/*unsigned long now; */ /*unsigned long now; */
if (ip_route_output(&rt, sip, tip, 0, 0) < 0) if (ip_route_output_key(&rt, &fl) < 0)
return 1; return 1;
if (rt->u.dst.dev != dev) { if (rt->u.dst.dev != dev) {
NET_INC_STATS_BH(ArpFilter); NET_INC_STATS_BH(ArpFilter);
...@@ -890,8 +892,10 @@ int arp_req_set(struct arpreq *r, struct net_device * dev) ...@@ -890,8 +892,10 @@ int arp_req_set(struct arpreq *r, struct net_device * dev)
if (r->arp_flags & ATF_PERM) if (r->arp_flags & ATF_PERM)
r->arp_flags |= ATF_COM; r->arp_flags |= ATF_COM;
if (dev == NULL) { if (dev == NULL) {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
.tos = RTO_ONLINK } } };
struct rtable * rt; struct rtable * rt;
if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0) if ((err = ip_route_output_key(&rt, &fl)) != 0)
return err; return err;
dev = rt->u.dst.dev; dev = rt->u.dst.dev;
ip_rt_put(rt); ip_rt_put(rt);
...@@ -974,8 +978,10 @@ int arp_req_delete(struct arpreq *r, struct net_device * dev) ...@@ -974,8 +978,10 @@ int arp_req_delete(struct arpreq *r, struct net_device * dev)
} }
if (dev == NULL) { if (dev == NULL) {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
.tos = RTO_ONLINK } } };
struct rtable * rt; struct rtable * rt;
if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0) if ((err = ip_route_output_key(&rt, &fl)) != 0)
return err; return err;
dev = rt->u.dst.dev; dev = rt->u.dst.dev;
ip_rt_put(rt); ip_rt_put(rt);
......
...@@ -144,17 +144,15 @@ fib_get_procinfo(char *buffer, char **start, off_t offset, int length) ...@@ -144,17 +144,15 @@ fib_get_procinfo(char *buffer, char **start, off_t offset, int length)
struct net_device * ip_dev_find(u32 addr) struct net_device * ip_dev_find(u32 addr)
{ {
struct rt_key key; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res; struct fib_result res;
struct net_device *dev = NULL; struct net_device *dev = NULL;
memset(&key, 0, sizeof(key));
key.dst = addr;
#ifdef CONFIG_IP_MULTIPLE_TABLES #ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL; res.r = NULL;
#endif #endif
if (!local_table || local_table->tb_lookup(local_table, &key, &res)) { if (!local_table || local_table->tb_lookup(local_table, &fl, &res)) {
return NULL; return NULL;
} }
if (res.type != RTN_LOCAL) if (res.type != RTN_LOCAL)
...@@ -170,7 +168,7 @@ struct net_device * ip_dev_find(u32 addr) ...@@ -170,7 +168,7 @@ struct net_device * ip_dev_find(u32 addr)
unsigned inet_addr_type(u32 addr) unsigned inet_addr_type(u32 addr)
{ {
struct rt_key key; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res; struct fib_result res;
unsigned ret = RTN_BROADCAST; unsigned ret = RTN_BROADCAST;
...@@ -179,15 +177,13 @@ unsigned inet_addr_type(u32 addr) ...@@ -179,15 +177,13 @@ unsigned inet_addr_type(u32 addr)
if (MULTICAST(addr)) if (MULTICAST(addr))
return RTN_MULTICAST; return RTN_MULTICAST;
memset(&key, 0, sizeof(key));
key.dst = addr;
#ifdef CONFIG_IP_MULTIPLE_TABLES #ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL; res.r = NULL;
#endif #endif
if (local_table) { if (local_table) {
ret = RTN_UNICAST; ret = RTN_UNICAST;
if (local_table->tb_lookup(local_table, &key, &res) == 0) { if (local_table->tb_lookup(local_table, &fl, &res) == 0) {
ret = res.type; ret = res.type;
fib_res_put(&res); fib_res_put(&res);
} }
...@@ -207,18 +203,15 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, ...@@ -207,18 +203,15 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
struct net_device *dev, u32 *spec_dst, u32 *itag) struct net_device *dev, u32 *spec_dst, u32 *itag)
{ {
struct in_device *in_dev; struct in_device *in_dev;
struct rt_key key; struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = src,
.saddr = dst,
.tos = tos } },
.iif = oif };
struct fib_result res; struct fib_result res;
int no_addr, rpf; int no_addr, rpf;
int ret; int ret;
key.dst = src;
key.src = dst;
key.tos = tos;
key.oif = 0;
key.iif = oif;
key.scope = RT_SCOPE_UNIVERSE;
no_addr = rpf = 0; no_addr = rpf = 0;
read_lock(&inetdev_lock); read_lock(&inetdev_lock);
in_dev = __in_dev_get(dev); in_dev = __in_dev_get(dev);
...@@ -231,7 +224,7 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, ...@@ -231,7 +224,7 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
if (in_dev == NULL) if (in_dev == NULL)
goto e_inval; goto e_inval;
if (fib_lookup(&key, &res)) if (fib_lookup(&fl, &res))
goto last_resort; goto last_resort;
if (res.type != RTN_UNICAST) if (res.type != RTN_UNICAST)
goto e_inval_res; goto e_inval_res;
...@@ -252,10 +245,10 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, ...@@ -252,10 +245,10 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
goto last_resort; goto last_resort;
if (rpf) if (rpf)
goto e_inval; goto e_inval;
key.oif = dev->ifindex; fl.oif = dev->ifindex;
ret = 0; ret = 0;
if (fib_lookup(&key, &res) == 0) { if (fib_lookup(&fl, &res) == 0) {
if (res.type == RTN_UNICAST) { if (res.type == RTN_UNICAST) {
*spec_dst = FIB_RES_PREFSRC(res); *spec_dst = FIB_RES_PREFSRC(res);
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
......
...@@ -266,7 +266,7 @@ fn_new_zone(struct fn_hash *table, int z) ...@@ -266,7 +266,7 @@ fn_new_zone(struct fn_hash *table, int z)
} }
static int static int
fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result *res) fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
{ {
int err; int err;
struct fn_zone *fz; struct fn_zone *fz;
...@@ -275,7 +275,7 @@ fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result ...@@ -275,7 +275,7 @@ fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result
read_lock(&fib_hash_lock); read_lock(&fib_hash_lock);
for (fz = t->fn_zone_list; fz; fz = fz->fz_next) { for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
struct fib_node *f; struct fib_node *f;
fn_key_t k = fz_key(key->dst, fz); fn_key_t k = fz_key(flp->fl4_dst, fz);
for (f = fz_chain(k, fz); f; f = f->fn_next) { for (f = fz_chain(k, fz); f; f = f->fn_next) {
if (!fn_key_eq(k, f->fn_key)) { if (!fn_key_eq(k, f->fn_key)) {
...@@ -285,17 +285,17 @@ fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result ...@@ -285,17 +285,17 @@ fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result
continue; continue;
} }
#ifdef CONFIG_IP_ROUTE_TOS #ifdef CONFIG_IP_ROUTE_TOS
if (f->fn_tos && f->fn_tos != key->tos) if (f->fn_tos && f->fn_tos != flp->fl4_tos)
continue; continue;
#endif #endif
f->fn_state |= FN_S_ACCESSED; f->fn_state |= FN_S_ACCESSED;
if (f->fn_state&FN_S_ZOMBIE) if (f->fn_state&FN_S_ZOMBIE)
continue; continue;
if (f->fn_scope < key->scope) if (f->fn_scope < flp->fl4_scope)
continue; continue;
err = fib_semantic_match(f->fn_type, FIB_INFO(f), key, res); err = fib_semantic_match(f->fn_type, FIB_INFO(f), flp, res);
if (err == 0) { if (err == 0) {
res->type = f->fn_type; res->type = f->fn_type;
res->scope = f->fn_scope; res->scope = f->fn_scope;
...@@ -338,7 +338,7 @@ static int fib_detect_death(struct fib_info *fi, int order, ...@@ -338,7 +338,7 @@ static int fib_detect_death(struct fib_info *fi, int order,
} }
static void static void
fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, struct fib_result *res) fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
{ {
int order, last_idx; int order, last_idx;
struct fib_node *f; struct fib_node *f;
......
...@@ -307,28 +307,28 @@ static void fib_rules_attach(struct net_device *dev) ...@@ -307,28 +307,28 @@ static void fib_rules_attach(struct net_device *dev)
} }
} }
int fib_lookup(const struct rt_key *key, struct fib_result *res) int fib_lookup(const struct flowi *flp, struct fib_result *res)
{ {
int err; int err;
struct fib_rule *r, *policy; struct fib_rule *r, *policy;
struct fib_table *tb; struct fib_table *tb;
u32 daddr = key->dst; u32 daddr = flp->fl4_dst;
u32 saddr = key->src; u32 saddr = flp->fl4_src;
FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ", FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
NIPQUAD(key->dst), NIPQUAD(key->src)); NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src));
read_lock(&fib_rules_lock); read_lock(&fib_rules_lock);
for (r = fib_rules; r; r=r->r_next) { for (r = fib_rules; r; r=r->r_next) {
if (((saddr^r->r_src) & r->r_srcmask) || if (((saddr^r->r_src) & r->r_srcmask) ||
((daddr^r->r_dst) & r->r_dstmask) || ((daddr^r->r_dst) & r->r_dstmask) ||
#ifdef CONFIG_IP_ROUTE_TOS #ifdef CONFIG_IP_ROUTE_TOS
(r->r_tos && r->r_tos != key->tos) || (r->r_tos && r->r_tos != flp->fl4_tos) ||
#endif #endif
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
(r->r_fwmark && r->r_fwmark != key->fwmark) || (r->r_fwmark && r->r_fwmark != flp->fl4_fwmark) ||
#endif #endif
(r->r_ifindex && r->r_ifindex != key->iif)) (r->r_ifindex && r->r_ifindex != flp->iif))
continue; continue;
FRprintk("tb %d r %d ", r->r_table, r->r_action); FRprintk("tb %d r %d ", r->r_table, r->r_action);
...@@ -351,7 +351,7 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action); ...@@ -351,7 +351,7 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action);
if ((tb = fib_get_table(r->r_table)) == NULL) if ((tb = fib_get_table(r->r_table)) == NULL)
continue; continue;
err = tb->tb_lookup(tb, key, res); err = tb->tb_lookup(tb, flp, res);
if (err == 0) { if (err == 0) {
res->r = policy; res->r = policy;
if (policy) if (policy)
...@@ -369,13 +369,13 @@ FRprintk("FAILURE\n"); ...@@ -369,13 +369,13 @@ FRprintk("FAILURE\n");
return -ENETUNREACH; return -ENETUNREACH;
} }
void fib_select_default(const struct rt_key *key, struct fib_result *res) void fib_select_default(const struct flowi *flp, struct fib_result *res)
{ {
if (res->r && res->r->r_action == RTN_UNICAST && if (res->r && res->r->r_action == RTN_UNICAST &&
FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) { FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
struct fib_table *tb; struct fib_table *tb;
if ((tb = fib_get_table(res->r->r_table)) != NULL) if ((tb = fib_get_table(res->r->r_table)) != NULL)
tb->tb_select_default(tb, key, res); tb->tb_select_default(tb, flp, res);
} }
} }
......
...@@ -349,7 +349,6 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n ...@@ -349,7 +349,6 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n
int err; int err;
if (nh->nh_gw) { if (nh->nh_gw) {
struct rt_key key;
struct fib_result res; struct fib_result res;
#ifdef CONFIG_IP_ROUTE_PERVASIVE #ifdef CONFIG_IP_ROUTE_PERVASIVE
...@@ -372,16 +371,18 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n ...@@ -372,16 +371,18 @@ static int fib_check_nh(const struct rtmsg *r, struct fib_info *fi, struct fib_n
nh->nh_scope = RT_SCOPE_LINK; nh->nh_scope = RT_SCOPE_LINK;
return 0; return 0;
} }
memset(&key, 0, sizeof(key)); {
key.dst = nh->nh_gw; struct flowi fl = { .nl_u = { .ip4_u =
key.oif = nh->nh_oif; { .daddr = nh->nh_gw,
key.scope = r->rtm_scope + 1; .scope = r->rtm_scope + 1 } },
.oif = nh->nh_oif };
/* It is not necessary, but requires a bit of thinking */
if (key.scope < RT_SCOPE_LINK) /* It is not necessary, but requires a bit of thinking */
key.scope = RT_SCOPE_LINK; if (fl.fl4_scope < RT_SCOPE_LINK)
if ((err = fib_lookup(&key, &res)) != 0) fl.fl4_scope = RT_SCOPE_LINK;
return err; if ((err = fib_lookup(&fl, &res)) != 0)
return err;
}
err = -EINVAL; err = -EINVAL;
if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
goto out; goto out;
...@@ -578,7 +579,7 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta, ...@@ -578,7 +579,7 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
} }
int int
fib_semantic_match(int type, struct fib_info *fi, const struct rt_key *key, struct fib_result *res) fib_semantic_match(int type, struct fib_info *fi, const struct flowi *flp, struct fib_result *res)
{ {
int err = fib_props[type].error; int err = fib_props[type].error;
...@@ -603,7 +604,7 @@ fib_semantic_match(int type, struct fib_info *fi, const struct rt_key *key, stru ...@@ -603,7 +604,7 @@ fib_semantic_match(int type, struct fib_info *fi, const struct rt_key *key, stru
for_nexthops(fi) { for_nexthops(fi) {
if (nh->nh_flags&RTNH_F_DEAD) if (nh->nh_flags&RTNH_F_DEAD)
continue; continue;
if (!key->oif || key->oif == nh->nh_oif) if (!flp->oif || flp->oif == nh->nh_oif)
break; break;
} }
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
...@@ -949,7 +950,7 @@ int fib_sync_up(struct net_device *dev) ...@@ -949,7 +950,7 @@ int fib_sync_up(struct net_device *dev)
fair weighted route distribution. fair weighted route distribution.
*/ */
void fib_select_multipath(const struct rt_key *key, struct fib_result *res) void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
{ {
struct fib_info *fi = res->fi; struct fib_info *fi = res->fi;
int w; int w;
......
...@@ -418,9 +418,14 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) ...@@ -418,9 +418,14 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
if (ipc.opt->srr) if (ipc.opt->srr)
daddr = icmp_param->replyopts.faddr; daddr = icmp_param->replyopts.faddr;
} }
if (ip_route_output(&rt, daddr, rt->rt_spec_dst, {
RT_TOS(skb->nh.iph->tos), 0)) struct flowi fl = { .nl_u = { .ip4_u =
goto out_unlock; { .daddr = daddr,
.saddr = rt->rt_spec_dst,
.tos = RT_TOS(skb->nh.iph->tos) } } };
if (ip_route_output_key(&rt, &fl))
goto out_unlock;
}
if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type, if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
icmp_param->data.icmph.code)) { icmp_param->data.icmph.code)) {
ip_build_xmit(sk, icmp_glue_bits, icmp_param, ip_build_xmit(sk, icmp_glue_bits, icmp_param,
...@@ -526,8 +531,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) ...@@ -526,8 +531,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
* Restore original addresses if packet has been translated. * Restore original addresses if packet has been translated.
*/ */
if (rt->rt_flags & RTCF_NAT && IPCB(skb_in)->flags & IPSKB_TRANSLATED) { if (rt->rt_flags & RTCF_NAT && IPCB(skb_in)->flags & IPSKB_TRANSLATED) {
iph->daddr = rt->key.dst; iph->daddr = rt->fl.fl4_dst;
iph->saddr = rt->key.src; iph->saddr = rt->fl.fl4_src;
} }
#endif #endif
...@@ -539,9 +544,13 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) ...@@ -539,9 +544,13 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
IPTOS_PREC_INTERNETCONTROL) : IPTOS_PREC_INTERNETCONTROL) :
iph->tos; iph->tos;
if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) {
goto out_unlock; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
.saddr = saddr,
.tos = RT_TOS(tos) } } };
if (ip_route_output_key(&rt, &fl))
goto out_unlock;
}
if (ip_options_echo(&icmp_param.replyopts, skb_in)) if (ip_options_echo(&icmp_param.replyopts, skb_in))
goto ende; goto ende;
...@@ -563,9 +572,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) ...@@ -563,9 +572,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
ipc.addr = iph->saddr; ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts; ipc.opt = &icmp_param.replyopts;
if (icmp_param.replyopts.srr) { if (icmp_param.replyopts.srr) {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = icmp_param.replyopts.faddr,
.saddr = saddr,
.tos = RT_TOS(tos) } } };
ip_rt_put(rt); ip_rt_put(rt);
if (ip_route_output(&rt, icmp_param.replyopts.faddr, if (ip_route_output_key(&rt, &fl))
saddr, RT_TOS(tos), 0))
goto out_unlock; goto out_unlock;
} }
......
...@@ -207,8 +207,12 @@ static int igmp_send_report(struct net_device *dev, u32 group, int type) ...@@ -207,8 +207,12 @@ static int igmp_send_report(struct net_device *dev, u32 group, int type)
if (type == IGMP_HOST_LEAVE_MESSAGE) if (type == IGMP_HOST_LEAVE_MESSAGE)
dst = IGMP_ALL_ROUTER; dst = IGMP_ALL_ROUTER;
if (ip_route_output(&rt, dst, 0, 0, dev->ifindex)) {
return -1; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst } },
.oif = dev->ifindex };
if (ip_route_output_key(&rt, &fl))
return -1;
}
if (rt->rt_src == 0) { if (rt->rt_src == 0) {
ip_rt_put(rt); ip_rt_put(rt);
return -1; return -1;
...@@ -374,7 +378,7 @@ int igmp_rcv(struct sk_buff *skb) ...@@ -374,7 +378,7 @@ int igmp_rcv(struct sk_buff *skb)
case IGMP_HOST_MEMBERSHIP_REPORT: case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMP_HOST_NEW_MEMBERSHIP_REPORT: case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
/* Is it our report looped back? */ /* Is it our report looped back? */
if (((struct rtable*)skb->dst)->key.iif == 0) if (((struct rtable*)skb->dst)->fl.iif == 0)
break; break;
igmp_heard_report(in_dev, ih->group); igmp_heard_report(in_dev, ih->group);
break; break;
...@@ -608,6 +612,8 @@ void ip_mc_destroy_dev(struct in_device *in_dev) ...@@ -608,6 +612,8 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
{ {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = imr->imr_address.s_addr } } };
struct rtable *rt; struct rtable *rt;
struct net_device *dev = NULL; struct net_device *dev = NULL;
struct in_device *idev = NULL; struct in_device *idev = NULL;
...@@ -619,7 +625,7 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) ...@@ -619,7 +625,7 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
__dev_put(dev); __dev_put(dev);
} }
if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) { if (!dev && !ip_route_output_key(&rt, &fl)) {
dev = rt->u.dst.dev; dev = rt->u.dst.dev;
ip_rt_put(rt); ip_rt_put(rt);
} }
......
...@@ -412,6 +412,7 @@ void ipgre_err(struct sk_buff *skb, u32 info) ...@@ -412,6 +412,7 @@ void ipgre_err(struct sk_buff *skb, u32 info)
u16 flags; u16 flags;
int grehlen = (iph->ihl<<2) + 4; int grehlen = (iph->ihl<<2) + 4;
struct sk_buff *skb2; struct sk_buff *skb2;
struct flowi fl;
struct rtable *rt; struct rtable *rt;
if (p[1] != htons(ETH_P_IP)) if (p[1] != htons(ETH_P_IP))
...@@ -488,7 +489,10 @@ void ipgre_err(struct sk_buff *skb, u32 info) ...@@ -488,7 +489,10 @@ void ipgre_err(struct sk_buff *skb, u32 info)
skb2->nh.raw = skb2->data; skb2->nh.raw = skb2->data;
/* Try to guess incoming interface */ /* Try to guess incoming interface */
if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) { memset(&fl, 0, sizeof(fl));
fl.fl4_dst = eiph->saddr;
fl.fl4_tos = RT_TOS(eiph->tos);
if (ip_route_output_key(&rt, &fl)) {
kfree_skb(skb2); kfree_skb(skb2);
return; return;
} }
...@@ -498,7 +502,10 @@ void ipgre_err(struct sk_buff *skb, u32 info) ...@@ -498,7 +502,10 @@ void ipgre_err(struct sk_buff *skb, u32 info)
if (rt->rt_flags&RTCF_LOCAL) { if (rt->rt_flags&RTCF_LOCAL) {
ip_rt_put(rt); ip_rt_put(rt);
rt = NULL; rt = NULL;
if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) || fl.fl4_dst = eiph->daddr;
fl.fl4_src = eiph->saddr;
fl.fl4_tos = eiph->tos;
if (ip_route_output_key(&rt, &fl) ||
rt->u.dst.dev->type != ARPHRD_IPGRE) { rt->u.dst.dev->type != ARPHRD_IPGRE) {
ip_rt_put(rt); ip_rt_put(rt);
kfree_skb(skb2); kfree_skb(skb2);
...@@ -619,7 +626,7 @@ int ipgre_rcv(struct sk_buff *skb) ...@@ -619,7 +626,7 @@ int ipgre_rcv(struct sk_buff *skb)
#ifdef CONFIG_NET_IPGRE_BROADCAST #ifdef CONFIG_NET_IPGRE_BROADCAST
if (MULTICAST(iph->daddr)) { if (MULTICAST(iph->daddr)) {
/* Looped back packet, drop it! */ /* Looped back packet, drop it! */
if (((struct rtable*)skb->dst)->key.iif == 0) if (((struct rtable*)skb->dst)->fl.iif == 0)
goto drop; goto drop;
tunnel->stat.multicast++; tunnel->stat.multicast++;
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
...@@ -749,9 +756,16 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -749,9 +756,16 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
tos &= ~1; tos &= ~1;
} }
if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) { {
tunnel->stat.tx_carrier_errors++; struct flowi fl = { .nl_u = { .ip4_u =
goto tx_error; { .daddr = dst,
.saddr = tiph->saddr,
.tos = RT_TOS(tos) } },
.oif = tunnel->parms.link };
if (ip_route_output_key(&rt, &fl)) {
tunnel->stat.tx_carrier_errors++;
goto tx_error;
}
} }
tdev = rt->u.dst.dev; tdev = rt->u.dst.dev;
...@@ -1104,10 +1118,13 @@ static int ipgre_open(struct net_device *dev) ...@@ -1104,10 +1118,13 @@ static int ipgre_open(struct net_device *dev)
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
if (MULTICAST(t->parms.iph.daddr)) { if (MULTICAST(t->parms.iph.daddr)) {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = t->parms.iph.daddr,
.saddr = t->parms.iph.saddr,
.tos = RT_TOS(t->parms.iph.tos) } },
.oif = t->parms.link };
struct rtable *rt; struct rtable *rt;
if (ip_route_output(&rt, t->parms.iph.daddr, if (ip_route_output_key(&rt, &fl)) {
t->parms.iph.saddr, RT_TOS(t->parms.iph.tos),
t->parms.link)) {
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
} }
...@@ -1177,8 +1194,13 @@ static int ipgre_tunnel_init(struct net_device *dev) ...@@ -1177,8 +1194,13 @@ static int ipgre_tunnel_init(struct net_device *dev)
/* Guess output device to choose reasonable mtu and hard_header_len */ /* Guess output device to choose reasonable mtu and hard_header_len */
if (iph->daddr) { if (iph->daddr) {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = iph->daddr,
.saddr = iph->saddr,
.tos = RT_TOS(iph->tos) } },
.oif = tunnel->parms.link };
struct rtable *rt; struct rtable *rt;
if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) { if (!ip_route_output_key(&rt, &fl)) {
tdev = rt->u.dst.dev; tdev = rt->u.dst.dev;
ip_rt_put(rt); ip_rt_put(rt);
} }
......
...@@ -117,23 +117,21 @@ ip_do_nat(struct sk_buff *skb) ...@@ -117,23 +117,21 @@ ip_do_nat(struct sk_buff *skb)
if (rt->rt_flags&RTCF_SNAT) { if (rt->rt_flags&RTCF_SNAT) {
if (ciph->daddr != osaddr) { if (ciph->daddr != osaddr) {
struct fib_result res; struct fib_result res;
struct rt_key key;
unsigned flags = 0; unsigned flags = 0;
struct flowi fl = { .nl_u =
key.src = ciph->daddr; { .ip4_u =
key.dst = ciph->saddr; { .daddr = ciph->saddr,
key.iif = skb->dev->ifindex; .saddr = ciph->daddr,
key.oif = 0;
#ifdef CONFIG_IP_ROUTE_TOS #ifdef CONFIG_IP_ROUTE_TOS
key.tos = RT_TOS(ciph->tos); .tos = RT_TOS(ciph->tos)
#endif
#ifdef CONFIG_IP_ROUTE_FWMARK
key.fwmark = 0;
#endif #endif
} },
.iif = skb->dev->ifindex };
/* Use fib_lookup() until we get our own /* Use fib_lookup() until we get our own
* hash table of NATed hosts -- Rani * hash table of NATed hosts -- Rani
*/ */
if (fib_lookup(&key, &res) == 0) { if (fib_lookup(&fl, &res) == 0) {
if (res.r) { if (res.r) {
ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags); ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
if (ciph->daddr != idaddr) if (ciph->daddr != idaddr)
......
...@@ -372,14 +372,20 @@ int ip_queue_xmit(struct sk_buff *skb) ...@@ -372,14 +372,20 @@ int ip_queue_xmit(struct sk_buff *skb)
if(opt && opt->srr) if(opt && opt->srr)
daddr = opt->faddr; daddr = opt->faddr;
/* If this fails, retransmit mechanism of transport layer will {
* keep trying until route appears or the connection times itself struct flowi fl = { .nl_u = { .ip4_u =
* out. { .daddr = daddr,
*/ .saddr = inet->saddr,
if (ip_route_output(&rt, daddr, inet->saddr, .tos = RT_CONN_FLAGS(sk) } },
RT_CONN_FLAGS(sk), .oif = sk->bound_dev_if };
sk->bound_dev_if))
goto no_route; /* If this fails, retransmit mechanism of transport layer will
* keep trying until route appears or the connection times itself
* out.
*/
if (ip_route_output_key(&rt, &fl))
goto no_route;
}
__sk_dst_set(sk, &rt->u.dst); __sk_dst_set(sk, &rt->u.dst);
tcp_v4_setup_caps(sk, &rt->u.dst); tcp_v4_setup_caps(sk, &rt->u.dst);
} }
...@@ -991,8 +997,14 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar ...@@ -991,8 +997,14 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
daddr = replyopts.opt.faddr; daddr = replyopts.opt.faddr;
} }
if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) {
return; struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = rt->rt_spec_dst,
.tos = RT_TOS(skb->nh.iph->tos) } } };
if (ip_route_output_key(&rt, &fl))
return;
}
/* And let IP do all the hard work. /* And let IP do all the hard work.
......
...@@ -355,6 +355,7 @@ void ipip_err(struct sk_buff *skb, u32 info) ...@@ -355,6 +355,7 @@ void ipip_err(struct sk_buff *skb, u32 info)
int rel_code = 0; int rel_code = 0;
int rel_info = 0; int rel_info = 0;
struct sk_buff *skb2; struct sk_buff *skb2;
struct flowi fl;
struct rtable *rt; struct rtable *rt;
if (len < hlen + sizeof(struct iphdr)) if (len < hlen + sizeof(struct iphdr))
...@@ -417,7 +418,10 @@ void ipip_err(struct sk_buff *skb, u32 info) ...@@ -417,7 +418,10 @@ void ipip_err(struct sk_buff *skb, u32 info)
skb2->nh.raw = skb2->data; skb2->nh.raw = skb2->data;
/* Try to guess incoming interface */ /* Try to guess incoming interface */
if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) { memset(&fl, 0, sizeof(fl));
fl.fl4_daddr = eiph->saddr;
fl.fl4_tos = RT_TOS(eiph->tos);
if (ip_route_output_key(&rt, &key)) {
kfree_skb(skb2); kfree_skb(skb2);
return; return;
} }
...@@ -427,7 +431,10 @@ void ipip_err(struct sk_buff *skb, u32 info) ...@@ -427,7 +431,10 @@ void ipip_err(struct sk_buff *skb, u32 info)
if (rt->rt_flags&RTCF_LOCAL) { if (rt->rt_flags&RTCF_LOCAL) {
ip_rt_put(rt); ip_rt_put(rt);
rt = NULL; rt = NULL;
if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) || fl.fl4_daddr = eiph->daddr;
fl.fl4_src = eiph->saddr;
fl.fl4_tos = eiph->tos;
if (ip_route_output_key(&rt, &fl) ||
rt->u.dst.dev->type != ARPHRD_IPGRE) { rt->u.dst.dev->type != ARPHRD_IPGRE) {
ip_rt_put(rt); ip_rt_put(rt);
kfree_skb(skb2); kfree_skb(skb2);
...@@ -560,9 +567,16 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -560,9 +567,16 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_error_icmp; goto tx_error_icmp;
} }
if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) { {
tunnel->stat.tx_carrier_errors++; struct flowi fl = { .nl_u = { .ip4_u =
goto tx_error_icmp; { .daddr = dst,
.saddr = tiph->saddr,
.tos = RT_TOS(tos) } },
.oif = tunnel->parms.link };
if (ip_route_output_key(&rt, &fl)) {
tunnel->stat.tx_carrier_errors++;
goto tx_error_icmp;
}
} }
tdev = rt->u.dst.dev; tdev = rt->u.dst.dev;
...@@ -822,8 +836,13 @@ static int ipip_tunnel_init(struct net_device *dev) ...@@ -822,8 +836,13 @@ static int ipip_tunnel_init(struct net_device *dev)
ipip_tunnel_init_gen(dev); ipip_tunnel_init_gen(dev);
if (iph->daddr) { if (iph->daddr) {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = iph->daddr,
.saddr = iph->saddr,
.tos = RT_TOS(iph->tos) } },
.oif = tunnel->parms.link };
struct rtable *rt; struct rtable *rt;
if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) { if (!ip_route_output_key(&rt, &fl)) {
tdev = rt->u.dst.dev; tdev = rt->u.dst.dev;
ip_rt_put(rt); ip_rt_put(rt);
} }
......
...@@ -1146,11 +1146,20 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, ...@@ -1146,11 +1146,20 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c,
#endif #endif
if (vif->flags&VIFF_TUNNEL) { if (vif->flags&VIFF_TUNNEL) {
if (ip_route_output(&rt, vif->remote, vif->local, RT_TOS(iph->tos), vif->link)) struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = vif->remote,
.saddr = vif->local,
.tos = RT_TOS(iph->tos) } },
.oif = vif->link };
if (ip_route_output_key(&rt, &fl))
return; return;
encap = sizeof(struct iphdr); encap = sizeof(struct iphdr);
} else { } else {
if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos), vif->link)) struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = iph->daddr,
.tos = RT_TOS(iph->tos) } },
.oif = vif->link };
if (ip_route_output_key(&rt, &fl))
return; return;
} }
...@@ -1244,7 +1253,7 @@ int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local) ...@@ -1244,7 +1253,7 @@ int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
if (vif_table[vif].dev != skb->dev) { if (vif_table[vif].dev != skb->dev) {
int true_vifi; int true_vifi;
if (((struct rtable*)skb->dst)->key.iif == 0) { if (((struct rtable*)skb->dst)->fl.iif == 0) {
/* It is our own packet, looped back. /* It is our own packet, looped back.
Very complicated situation... Very complicated situation...
......
...@@ -68,12 +68,13 @@ do_masquerade(struct sk_buff **pskb, const struct net_device *dev) ...@@ -68,12 +68,13 @@ do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
/* Setup the masquerade, if not already */ /* Setup the masquerade, if not already */
if (!info->initialized) { if (!info->initialized) {
u_int32_t newsrc; u_int32_t newsrc;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->daddr } } };
struct rtable *rt; struct rtable *rt;
struct ip_nat_multi_range range; struct ip_nat_multi_range range;
/* Pass 0 instead of saddr, since it's going to be changed /* Pass 0 instead of saddr, since it's going to be changed
anyway. */ anyway. */
if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) { if (ip_route_output_key(&rt, &fl) != 0) {
DEBUGP("ipnat_rule_masquerade: Can't reroute.\n"); DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
return NF_DROP; return NF_DROP;
} }
......
...@@ -209,10 +209,11 @@ find_appropriate_src(const struct ip_conntrack_tuple *tuple, ...@@ -209,10 +209,11 @@ find_appropriate_src(const struct ip_conntrack_tuple *tuple,
static int static int
do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp) do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
{ {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = var_ip } } };
struct rtable *rt; struct rtable *rt;
/* FIXME: IPTOS_TOS(iph->tos) --RR */ /* FIXME: IPTOS_TOS(iph->tos) --RR */
if (ip_route_output(&rt, var_ip, 0, 0, 0) != 0) { if (ip_route_output_key(&rt, &fl) != 0) {
DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n", DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
NIPQUAD(var_ip)); NIPQUAD(var_ip));
return 0; return 0;
......
...@@ -69,7 +69,6 @@ masquerade_target(struct sk_buff **pskb, ...@@ -69,7 +69,6 @@ masquerade_target(struct sk_buff **pskb,
struct ip_nat_multi_range newrange; struct ip_nat_multi_range newrange;
u_int32_t newsrc; u_int32_t newsrc;
struct rtable *rt; struct rtable *rt;
struct rt_key key;
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
...@@ -84,17 +83,21 @@ masquerade_target(struct sk_buff **pskb, ...@@ -84,17 +83,21 @@ masquerade_target(struct sk_buff **pskb,
mr = targinfo; mr = targinfo;
key.dst = (*pskb)->nh.iph->daddr; {
key.src = 0; /* Unknown: that's what we're trying to establish */ struct flowi fl = { .nl_u = { .ip4_u =
key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN; { .daddr = (*pskb)->nh.iph->daddr,
key.oif = out->ifindex; .tos = (RT_TOS((*pskb)->nh.iph->tos) |
RTO_CONN),
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
key.fwmark = (*pskb)->nfmark; .fwmark = (*pskb)->nfmark
#endif #endif
if (ip_route_output_key(&rt, &key) != 0) { } },
/* Shouldn't happen */ .oif = out->ifindex };
printk("MASQUERADE: No route: Rusty's brain broke!\n"); if (ip_route_output_key(&rt, &fl) != 0) {
return NF_DROP; /* Shouldn't happen */
printk("MASQUERADE: No route: Rusty's brain broke!\n");
return NF_DROP;
}
} }
newsrc = rt->rt_src; newsrc = rt->rt_src;
......
...@@ -44,12 +44,13 @@ struct in_device; ...@@ -44,12 +44,13 @@ struct in_device;
static int route_mirror(struct sk_buff *skb) static int route_mirror(struct sk_buff *skb)
{ {
struct iphdr *iph = skb->nh.iph; struct iphdr *iph = skb->nh.iph;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
.saddr = iph->daddr,
.tos = RT_TOS(iph->tos) | RTO_CONN } } };
struct rtable *rt; struct rtable *rt;
/* Backwards */ /* Backwards */
if (ip_route_output(&rt, iph->saddr, iph->daddr, if (ip_route_output_key(&rt, &fl)) {
RT_TOS(iph->tos) | RTO_CONN,
0)) {
return 0; return 0;
} }
......
...@@ -130,12 +130,19 @@ static void send_reset(struct sk_buff *oldskb, int local) ...@@ -130,12 +130,19 @@ static void send_reset(struct sk_buff *oldskb, int local)
nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
nskb->nh.iph->ihl); nskb->nh.iph->ihl);
/* Routing: if not headed for us, route won't like source */ {
if (ip_route_output(&rt, nskb->nh.iph->daddr, struct flowi fl = { .nl_u = { .ip4_u =
local ? nskb->nh.iph->saddr : 0, { .daddr = nskb->nh.iph->daddr,
RT_TOS(nskb->nh.iph->tos) | RTO_CONN, .saddr = (local ?
0) != 0) nskb->nh.iph->saddr :
goto free_nskb; 0),
.tos = (RT_TOS(nskb->nh.iph->tos) |
RTO_CONN) } } };
/* Routing: if not headed for us, route won't like source */
if (ip_route_output_key(&rt, &fl))
goto free_nskb;
}
dst_release(nskb->dst); dst_release(nskb->dst);
nskb->dst = &rt->u.dst; nskb->dst = &rt->u.dst;
...@@ -207,9 +214,14 @@ static void send_unreach(struct sk_buff *skb_in, int code) ...@@ -207,9 +214,14 @@ static void send_unreach(struct sk_buff *skb_in, int code)
tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL; tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) {
return; struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = iph->saddr,
.saddr = saddr,
.tos = RT_TOS(tos) } } };
if (ip_route_output_key(&rt, &fl))
return;
}
/* RFC says return as much as we can without exceeding 576 bytes. */ /* RFC says return as much as we can without exceeding 576 bytes. */
length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr); length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr);
......
...@@ -402,8 +402,14 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len) ...@@ -402,8 +402,14 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len)
rfh.saddr = inet->mc_addr; rfh.saddr = inet->mc_addr;
} }
err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif); {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = rfh.saddr,
.tos = tos } },
.oif = ipc.oif };
err = ip_route_output_key(&rt, &fl);
}
if (err) if (err)
goto done; goto done;
......
...@@ -251,7 +251,7 @@ static int rt_cache_get_info(char *buffer, char **start, off_t offset, ...@@ -251,7 +251,7 @@ static int rt_cache_get_info(char *buffer, char **start, off_t offset,
(int)r->u.dst.advmss + 40, (int)r->u.dst.advmss + 40,
r->u.dst.window, r->u.dst.window,
(int)((r->u.dst.rtt >> 3) + r->u.dst.rttvar), (int)((r->u.dst.rtt >> 3) + r->u.dst.rttvar),
r->key.tos, r->fl.fl4_tos,
r->u.dst.hh ? r->u.dst.hh ?
atomic_read(&r->u.dst.hh->hh_refcnt) : atomic_read(&r->u.dst.hh->hh_refcnt) :
-1, -1,
...@@ -332,7 +332,7 @@ static __inline__ int rt_fast_clean(struct rtable *rth) ...@@ -332,7 +332,7 @@ static __inline__ int rt_fast_clean(struct rtable *rth)
/* Kill broadcast/multicast entries very aggresively, if they /* Kill broadcast/multicast entries very aggresively, if they
collide in hash table with more useful entries */ collide in hash table with more useful entries */
return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) && return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) &&
rth->key.iif && rth->u.rt_next; rth->fl.iif && rth->u.rt_next;
} }
static __inline__ int rt_valuable(struct rtable *rth) static __inline__ int rt_valuable(struct rtable *rth)
...@@ -621,7 +621,7 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) ...@@ -621,7 +621,7 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
write_lock_bh(&rt_hash_table[hash].lock); write_lock_bh(&rt_hash_table[hash].lock);
while ((rth = *rthp) != NULL) { while ((rth = *rthp) != NULL) {
if (memcmp(&rth->key, &rt->key, sizeof(rt->key)) == 0) { if (memcmp(&rth->fl, &rt->fl, sizeof(rt->fl)) == 0) {
/* Put it first */ /* Put it first */
*rthp = rth->u.rt_next; *rthp = rth->u.rt_next;
rth->u.rt_next = rt_hash_table[hash].chain; rth->u.rt_next = rt_hash_table[hash].chain;
...@@ -643,7 +643,7 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) ...@@ -643,7 +643,7 @@ static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp)
/* Try to bind route to arp only if it is output /* Try to bind route to arp only if it is output
route or unicast forwarding path. route or unicast forwarding path.
*/ */
if (rt->rt_type == RTN_UNICAST || rt->key.iif == 0) { if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
int err = arp_bind_neighbour(&rt->u.dst); int err = arp_bind_neighbour(&rt->u.dst);
if (err) { if (err) {
write_unlock_bh(&rt_hash_table[hash].lock); write_unlock_bh(&rt_hash_table[hash].lock);
...@@ -806,11 +806,11 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw, ...@@ -806,11 +806,11 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
while ((rth = *rthp) != NULL) { while ((rth = *rthp) != NULL) {
struct rtable *rt; struct rtable *rt;
if (rth->key.dst != daddr || if (rth->fl.fl4_dst != daddr ||
rth->key.src != skeys[i] || rth->fl.fl4_src != skeys[i] ||
rth->key.tos != tos || rth->fl.fl4_tos != tos ||
rth->key.oif != ikeys[k] || rth->fl.oif != ikeys[k] ||
rth->key.iif != 0) { rth->fl.iif != 0) {
rthp = &rth->u.rt_next; rthp = &rth->u.rt_next;
continue; continue;
} }
...@@ -901,14 +901,14 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) ...@@ -901,14 +901,14 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
ret = NULL; ret = NULL;
} else if ((rt->rt_flags & RTCF_REDIRECTED) || } else if ((rt->rt_flags & RTCF_REDIRECTED) ||
rt->u.dst.expires) { rt->u.dst.expires) {
unsigned hash = rt_hash_code(rt->key.dst, unsigned hash = rt_hash_code(rt->fl.fl4_dst,
rt->key.src ^ rt->fl.fl4_src ^
(rt->key.oif << 5), (rt->fl.oif << 5),
rt->key.tos); rt->fl.fl4_tos);
#if RT_CACHE_DEBUG >= 1 #if RT_CACHE_DEBUG >= 1
printk(KERN_DEBUG "ip_rt_advice: redirect to " printk(KERN_DEBUG "ip_rt_advice: redirect to "
"%u.%u.%u.%u/%02x dropped\n", "%u.%u.%u.%u/%02x dropped\n",
NIPQUAD(rt->rt_dst), rt->key.tos); NIPQUAD(rt->rt_dst), rt->fl.fl4_tos);
#endif #endif
rt_del(hash, rt); rt_del(hash, rt);
ret = NULL; ret = NULL;
...@@ -1052,12 +1052,12 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu) ...@@ -1052,12 +1052,12 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
read_lock(&rt_hash_table[hash].lock); read_lock(&rt_hash_table[hash].lock);
for (rth = rt_hash_table[hash].chain; rth; for (rth = rt_hash_table[hash].chain; rth;
rth = rth->u.rt_next) { rth = rth->u.rt_next) {
if (rth->key.dst == daddr && if (rth->fl.fl4_dst == daddr &&
rth->key.src == skeys[i] && rth->fl.fl4_src == skeys[i] &&
rth->rt_dst == daddr && rth->rt_dst == daddr &&
rth->rt_src == iph->saddr && rth->rt_src == iph->saddr &&
rth->key.tos == tos && rth->fl.fl4_tos == tos &&
rth->key.iif == 0 && rth->fl.iif == 0 &&
!(rth->u.dst.mxlock & (1 << RTAX_MTU))) { !(rth->u.dst.mxlock & (1 << RTAX_MTU))) {
unsigned short mtu = new_mtu; unsigned short mtu = new_mtu;
...@@ -1162,9 +1162,9 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt) ...@@ -1162,9 +1162,9 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
u32 src; u32 src;
struct fib_result res; struct fib_result res;
if (rt->key.iif == 0) if (rt->fl.iif == 0)
src = rt->rt_src; src = rt->rt_src;
else if (fib_lookup(&rt->key, &res) == 0) { else if (fib_lookup(&rt->fl, &res) == 0) {
#ifdef CONFIG_IP_ROUTE_NAT #ifdef CONFIG_IP_ROUTE_NAT
if (res.type == RTN_NAT) if (res.type == RTN_NAT)
src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
...@@ -1263,13 +1263,13 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1263,13 +1263,13 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
atomic_set(&rth->u.dst.__refcnt, 1); atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST; rth->u.dst.flags= DST_HOST;
rth->key.dst = daddr; rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr; rth->rt_dst = daddr;
rth->key.tos = tos; rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark = skb->nfmark; rth->fl.fl4_fwmark= skb->nfmark;
#endif #endif
rth->key.src = saddr; rth->fl.fl4_src = saddr;
rth->rt_src = saddr; rth->rt_src = saddr;
#ifdef CONFIG_IP_ROUTE_NAT #ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = daddr; rth->rt_dst_map = daddr;
...@@ -1279,10 +1279,10 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1279,10 +1279,10 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
rth->u.dst.tclassid = itag; rth->u.dst.tclassid = itag;
#endif #endif
rth->rt_iif = rth->rt_iif =
rth->key.iif = dev->ifindex; rth->fl.iif = dev->ifindex;
rth->u.dst.dev = &loopback_dev; rth->u.dst.dev = &loopback_dev;
dev_hold(rth->u.dst.dev); dev_hold(rth->u.dst.dev);
rth->key.oif = 0; rth->fl.oif = 0;
rth->rt_gateway = daddr; rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst; rth->rt_spec_dst= spec_dst;
rth->rt_type = RTN_MULTICAST; rth->rt_type = RTN_MULTICAST;
...@@ -1324,10 +1324,19 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1324,10 +1324,19 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
u8 tos, struct net_device *dev) u8 tos, struct net_device *dev)
{ {
struct rt_key key;
struct fib_result res; struct fib_result res;
struct in_device *in_dev = in_dev_get(dev); struct in_device *in_dev = in_dev_get(dev);
struct in_device *out_dev = NULL; struct in_device *out_dev = NULL;
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = saddr,
.tos = tos,
.scope = RT_SCOPE_UNIVERSE,
#ifdef CONFIG_IP_ROUTE_FWMARK
.fwmark = skb->nfmark
#endif
} },
.iif = dev->ifindex };
unsigned flags = 0; unsigned flags = 0;
u32 itag = 0; u32 itag = 0;
struct rtable * rth; struct rtable * rth;
...@@ -1341,17 +1350,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1341,17 +1350,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
if (!in_dev) if (!in_dev)
goto out; goto out;
key.dst = daddr; hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos);
key.src = saddr;
key.tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK
key.fwmark = skb->nfmark;
#endif
key.iif = dev->ifindex;
key.oif = 0;
key.scope = RT_SCOPE_UNIVERSE;
hash = rt_hash_code(daddr, saddr ^ (key.iif << 5), tos);
/* Check for the most weird martians, which can be not detected /* Check for the most weird martians, which can be not detected
by fib_lookup. by fib_lookup.
...@@ -1375,7 +1374,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1375,7 +1374,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
/* /*
* Now we are ready to route packet. * Now we are ready to route packet.
*/ */
if ((err = fib_lookup(&key, &res)) != 0) { if ((err = fib_lookup(&fl, &res)) != 0) {
if (!IN_DEV_FORWARD(in_dev)) if (!IN_DEV_FORWARD(in_dev))
goto e_inval; goto e_inval;
goto no_route; goto no_route;
...@@ -1395,17 +1394,17 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1395,17 +1394,17 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
src_map = fib_rules_policy(saddr, &res, &flags); src_map = fib_rules_policy(saddr, &res, &flags);
if (res.type == RTN_NAT) { if (res.type == RTN_NAT) {
key.dst = fib_rules_map_destination(daddr, &res); fl.fl4_dst = fib_rules_map_destination(daddr, &res);
fib_res_put(&res); fib_res_put(&res);
free_res = 0; free_res = 0;
if (fib_lookup(&key, &res)) if (fib_lookup(&fl, &res))
goto e_inval; goto e_inval;
free_res = 1; free_res = 1;
if (res.type != RTN_UNICAST) if (res.type != RTN_UNICAST)
goto e_inval; goto e_inval;
flags |= RTCF_DNAT; flags |= RTCF_DNAT;
} }
key.src = src_map; fl.fl4_src = src_map;
} }
#endif #endif
...@@ -1431,8 +1430,8 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1431,8 +1430,8 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
goto martian_destination; goto martian_destination;
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
if (res.fi->fib_nhs > 1 && key.oif == 0) if (res.fi->fib_nhs > 1 && fl.oif == 0)
fib_select_multipath(&key, &res); fib_select_multipath(&fl, &res);
#endif #endif
out_dev = in_dev_get(FIB_RES_DEV(res)); out_dev = in_dev_get(FIB_RES_DEV(res));
if (out_dev == NULL) { if (out_dev == NULL) {
...@@ -1469,26 +1468,26 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1469,26 +1468,26 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
atomic_set(&rth->u.dst.__refcnt, 1); atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST; rth->u.dst.flags= DST_HOST;
rth->key.dst = daddr; rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr; rth->rt_dst = daddr;
rth->key.tos = tos; rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark = skb->nfmark; rth->fl.fl4_fwmark= skb->nfmark;
#endif #endif
rth->key.src = saddr; rth->fl.fl4_src = saddr;
rth->rt_src = saddr; rth->rt_src = saddr;
rth->rt_gateway = daddr; rth->rt_gateway = daddr;
#ifdef CONFIG_IP_ROUTE_NAT #ifdef CONFIG_IP_ROUTE_NAT
rth->rt_src_map = key.src; rth->rt_src_map = fl.fl4_src;
rth->rt_dst_map = key.dst; rth->rt_dst_map = fl.fl4_dst;
if (flags&RTCF_DNAT) if (flags&RTCF_DNAT)
rth->rt_gateway = key.dst; rth->rt_gateway = fl.fl4_dst;
#endif #endif
rth->rt_iif = rth->rt_iif =
rth->key.iif = dev->ifindex; rth->fl.iif = dev->ifindex;
rth->u.dst.dev = out_dev->dev; rth->u.dst.dev = out_dev->dev;
dev_hold(rth->u.dst.dev); dev_hold(rth->u.dst.dev);
rth->key.oif = 0; rth->fl.oif = 0;
rth->rt_spec_dst= spec_dst; rth->rt_spec_dst= spec_dst;
rth->u.dst.input = ip_forward; rth->u.dst.input = ip_forward;
...@@ -1546,26 +1545,25 @@ out: return err; ...@@ -1546,26 +1545,25 @@ out: return err;
atomic_set(&rth->u.dst.__refcnt, 1); atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST; rth->u.dst.flags= DST_HOST;
rth->key.dst = daddr; rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr; rth->rt_dst = daddr;
rth->key.tos = tos; rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark = skb->nfmark; rth->fl.fl4_fwmark= skb->nfmark;
#endif #endif
rth->key.src = saddr; rth->fl.fl4_src = saddr;
rth->rt_src = saddr; rth->rt_src = saddr;
#ifdef CONFIG_IP_ROUTE_NAT #ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = key.dst; rth->rt_dst_map = fl.fl4_dst;
rth->rt_src_map = key.src; rth->rt_src_map = fl.fl4_src;
#endif #endif
#ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_NET_CLS_ROUTE
rth->u.dst.tclassid = itag; rth->u.dst.tclassid = itag;
#endif #endif
rth->rt_iif = rth->rt_iif =
rth->key.iif = dev->ifindex; rth->fl.iif = dev->ifindex;
rth->u.dst.dev = &loopback_dev; rth->u.dst.dev = &loopback_dev;
dev_hold(rth->u.dst.dev); dev_hold(rth->u.dst.dev);
rth->key.oif = 0;
rth->rt_gateway = daddr; rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst; rth->rt_spec_dst= spec_dst;
rth->u.dst.input= ip_local_deliver; rth->u.dst.input= ip_local_deliver;
...@@ -1643,14 +1641,14 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1643,14 +1641,14 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
read_lock(&rt_hash_table[hash].lock); read_lock(&rt_hash_table[hash].lock);
for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) {
if (rth->key.dst == daddr && if (rth->fl.fl4_dst == daddr &&
rth->key.src == saddr && rth->fl.fl4_src == saddr &&
rth->key.iif == iif && rth->fl.iif == iif &&
rth->key.oif == 0 && rth->fl.oif == 0 &&
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark == skb->nfmark && rth->fl.fl4_fwmark == skb->nfmark &&
#endif #endif
rth->key.tos == tos) { rth->fl.fl4_tos == tos) {
rth->u.dst.lastuse = jiffies; rth->u.dst.lastuse = jiffies;
dst_hold(&rth->u.dst); dst_hold(&rth->u.dst);
rth->u.dst.__use++; rth->u.dst.__use++;
...@@ -1699,9 +1697,22 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1699,9 +1697,22 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
* Major route resolver routine. * Major route resolver routine.
*/ */
int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
{ {
struct rt_key key; u32 tos = oldflp->fl4_tos & (IPTOS_RT_MASK | RTO_ONLINK);
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = oldflp->fl4_dst,
.saddr = oldflp->fl4_src,
.tos = tos & IPTOS_RT_MASK,
.scope = ((tos & RTO_ONLINK) ?
RT_SCOPE_LINK :
RT_SCOPE_UNIVERSE),
#ifdef CONFIG_IP_ROUTE_FWMARK
.fwmark = oldflp->fl4_fwmark
#endif
} },
.iif = loopback_dev.ifindex,
.oif = oldflp->oif };
struct fib_result res; struct fib_result res;
unsigned flags = 0; unsigned flags = 0;
struct rtable *rth; struct rtable *rth;
...@@ -1709,33 +1720,21 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1709,33 +1720,21 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
unsigned hash; unsigned hash;
int free_res = 0; int free_res = 0;
int err; int err;
u32 tos;
tos = oldkey->tos & (IPTOS_RT_MASK | RTO_ONLINK);
key.dst = oldkey->dst;
key.src = oldkey->src;
key.tos = tos & IPTOS_RT_MASK;
key.iif = loopback_dev.ifindex;
key.oif = oldkey->oif;
#ifdef CONFIG_IP_ROUTE_FWMARK
key.fwmark = oldkey->fwmark;
#endif
key.scope = (tos & RTO_ONLINK) ? RT_SCOPE_LINK :
RT_SCOPE_UNIVERSE;
res.fi = NULL; res.fi = NULL;
#ifdef CONFIG_IP_MULTIPLE_TABLES #ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL; res.r = NULL;
#endif #endif
if (oldkey->src) { if (oldflp->fl4_src) {
err = -EINVAL; err = -EINVAL;
if (MULTICAST(oldkey->src) || if (MULTICAST(oldflp->fl4_src) ||
BADCLASS(oldkey->src) || BADCLASS(oldflp->fl4_src) ||
ZERONET(oldkey->src)) ZERONET(oldflp->fl4_src))
goto out; goto out;
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
dev_out = ip_dev_find(oldkey->src); dev_out = ip_dev_find(oldflp->fl4_src);
if (dev_out == NULL) if (dev_out == NULL)
goto out; goto out;
...@@ -1747,8 +1746,8 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1747,8 +1746,8 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
of another iface. --ANK of another iface. --ANK
*/ */
if (oldkey->oif == 0 if (oldflp->oif == 0
&& (MULTICAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF)) { && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF)) {
/* Special hack: user can direct multicasts /* Special hack: user can direct multicasts
and limited broadcast via necessary interface and limited broadcast via necessary interface
without fiddling with IP_MULTICAST_IF or IP_PKTINFO. without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
...@@ -1764,15 +1763,15 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1764,15 +1763,15 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
Luckily, this hack is good workaround. Luckily, this hack is good workaround.
*/ */
key.oif = dev_out->ifindex; fl.oif = dev_out->ifindex;
goto make_route; goto make_route;
} }
if (dev_out) if (dev_out)
dev_put(dev_out); dev_put(dev_out);
dev_out = NULL; dev_out = NULL;
} }
if (oldkey->oif) { if (oldflp->oif) {
dev_out = dev_get_by_index(oldkey->oif); dev_out = dev_get_by_index(oldflp->oif);
err = -ENODEV; err = -ENODEV;
if (dev_out == NULL) if (dev_out == NULL)
goto out; goto out;
...@@ -1781,39 +1780,39 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1781,39 +1780,39 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
goto out; /* Wrong error code */ goto out; /* Wrong error code */
} }
if (LOCAL_MCAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF) { if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF) {
if (!key.src) if (!fl.fl4_src)
key.src = inet_select_addr(dev_out, 0, fl.fl4_src = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK); RT_SCOPE_LINK);
goto make_route; goto make_route;
} }
if (!key.src) { if (!fl.fl4_src) {
if (MULTICAST(oldkey->dst)) if (MULTICAST(oldflp->fl4_dst))
key.src = inet_select_addr(dev_out, 0, fl.fl4_src = inet_select_addr(dev_out, 0,
key.scope); fl.fl4_scope);
else if (!oldkey->dst) else if (!oldflp->fl4_dst)
key.src = inet_select_addr(dev_out, 0, fl.fl4_src = inet_select_addr(dev_out, 0,
RT_SCOPE_HOST); RT_SCOPE_HOST);
} }
} }
if (!key.dst) { if (!fl.fl4_dst) {
key.dst = key.src; fl.fl4_dst = fl.fl4_src;
if (!key.dst) if (!fl.fl4_dst)
key.dst = key.src = htonl(INADDR_LOOPBACK); fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK);
if (dev_out) if (dev_out)
dev_put(dev_out); dev_put(dev_out);
dev_out = &loopback_dev; dev_out = &loopback_dev;
dev_hold(dev_out); dev_hold(dev_out);
key.oif = loopback_dev.ifindex; fl.oif = loopback_dev.ifindex;
res.type = RTN_LOCAL; res.type = RTN_LOCAL;
flags |= RTCF_LOCAL; flags |= RTCF_LOCAL;
goto make_route; goto make_route;
} }
if (fib_lookup(&key, &res)) { if (fib_lookup(&fl, &res)) {
res.fi = NULL; res.fi = NULL;
if (oldkey->oif) { if (oldflp->oif) {
/* Apparently, routing tables are wrong. Assume, /* Apparently, routing tables are wrong. Assume,
that the destination is on link. that the destination is on link.
...@@ -1832,9 +1831,9 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1832,9 +1831,9 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
likely IPv6, but we do not. likely IPv6, but we do not.
*/ */
if (key.src == 0) if (fl.fl4_src == 0)
key.src = inet_select_addr(dev_out, 0, fl.fl4_src = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK); RT_SCOPE_LINK);
res.type = RTN_UNICAST; res.type = RTN_UNICAST;
goto make_route; goto make_route;
} }
...@@ -1849,13 +1848,13 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1849,13 +1848,13 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
goto e_inval; goto e_inval;
if (res.type == RTN_LOCAL) { if (res.type == RTN_LOCAL) {
if (!key.src) if (!fl.fl4_src)
key.src = key.dst; fl.fl4_src = fl.fl4_dst;
if (dev_out) if (dev_out)
dev_put(dev_out); dev_put(dev_out);
dev_out = &loopback_dev; dev_out = &loopback_dev;
dev_hold(dev_out); dev_hold(dev_out);
key.oif = dev_out->ifindex; fl.oif = dev_out->ifindex;
if (res.fi) if (res.fi)
fib_info_put(res.fi); fib_info_put(res.fi);
res.fi = NULL; res.fi = NULL;
...@@ -1864,31 +1863,31 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1864,31 +1863,31 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
} }
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
if (res.fi->fib_nhs > 1 && key.oif == 0) if (res.fi->fib_nhs > 1 && fl.oif == 0)
fib_select_multipath(&key, &res); fib_select_multipath(&fl, &res);
else else
#endif #endif
if (!res.prefixlen && res.type == RTN_UNICAST && !key.oif) if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
fib_select_default(&key, &res); fib_select_default(&fl, &res);
if (!key.src) if (!fl.fl4_src)
key.src = FIB_RES_PREFSRC(res); fl.fl4_src = FIB_RES_PREFSRC(res);
if (dev_out) if (dev_out)
dev_put(dev_out); dev_put(dev_out);
dev_out = FIB_RES_DEV(res); dev_out = FIB_RES_DEV(res);
dev_hold(dev_out); dev_hold(dev_out);
key.oif = dev_out->ifindex; fl.oif = dev_out->ifindex;
make_route: make_route:
if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK)) if (LOOPBACK(fl.fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
goto e_inval; goto e_inval;
if (key.dst == 0xFFFFFFFF) if (fl.fl4_dst == 0xFFFFFFFF)
res.type = RTN_BROADCAST; res.type = RTN_BROADCAST;
else if (MULTICAST(key.dst)) else if (MULTICAST(fl.fl4_dst))
res.type = RTN_MULTICAST; res.type = RTN_MULTICAST;
else if (BADCLASS(key.dst) || ZERONET(key.dst)) else if (BADCLASS(fl.fl4_dst) || ZERONET(fl.fl4_dst))
goto e_inval; goto e_inval;
if (dev_out->flags & IFF_LOOPBACK) if (dev_out->flags & IFF_LOOPBACK)
...@@ -1904,7 +1903,7 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1904,7 +1903,7 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
flags |= RTCF_MULTICAST|RTCF_LOCAL; flags |= RTCF_MULTICAST|RTCF_LOCAL;
read_lock(&inetdev_lock); read_lock(&inetdev_lock);
if (!__in_dev_get(dev_out) || if (!__in_dev_get(dev_out) ||
!ip_check_mc(__in_dev_get(dev_out), oldkey->dst)) !ip_check_mc(__in_dev_get(dev_out), oldflp->fl4_dst))
flags &= ~RTCF_LOCAL; flags &= ~RTCF_LOCAL;
read_unlock(&inetdev_lock); read_unlock(&inetdev_lock);
/* If multicast route do not exist use /* If multicast route do not exist use
...@@ -1923,25 +1922,24 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1923,25 +1922,24 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
atomic_set(&rth->u.dst.__refcnt, 1); atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST; rth->u.dst.flags= DST_HOST;
rth->key.dst = oldkey->dst; rth->fl.fl4_dst = oldflp->fl4_dst;
rth->key.tos = tos; rth->fl.fl4_tos = tos;
rth->key.src = oldkey->src; rth->fl.fl4_src = oldflp->fl4_src;
rth->key.iif = 0; rth->fl.oif = oldflp->oif;
rth->key.oif = oldkey->oif;
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark = oldkey->fwmark; rth->fl.fl4_fwmark= oldflp->fl4_fwmark;
#endif #endif
rth->rt_dst = key.dst; rth->rt_dst = fl.fl4_dst;
rth->rt_src = key.src; rth->rt_src = fl.fl4_src;
#ifdef CONFIG_IP_ROUTE_NAT #ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = key.dst; rth->rt_dst_map = fl.fl4_dst;
rth->rt_src_map = key.src; rth->rt_src_map = fl.fl4_src;
#endif #endif
rth->rt_iif = oldkey->oif ? : dev_out->ifindex; rth->rt_iif = oldflp->oif ? : dev_out->ifindex;
rth->u.dst.dev = dev_out; rth->u.dst.dev = dev_out;
dev_hold(dev_out); dev_hold(dev_out);
rth->rt_gateway = key.dst; rth->rt_gateway = fl.fl4_dst;
rth->rt_spec_dst= key.src; rth->rt_spec_dst= fl.fl4_src;
rth->u.dst.output=ip_output; rth->u.dst.output=ip_output;
...@@ -1949,10 +1947,10 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1949,10 +1947,10 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
if (flags & RTCF_LOCAL) { if (flags & RTCF_LOCAL) {
rth->u.dst.input = ip_local_deliver; rth->u.dst.input = ip_local_deliver;
rth->rt_spec_dst = key.dst; rth->rt_spec_dst = fl.fl4_dst;
} }
if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
rth->rt_spec_dst = key.src; rth->rt_spec_dst = fl.fl4_src;
if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) { if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) {
rth->u.dst.output = ip_mc_output; rth->u.dst.output = ip_mc_output;
rt_cache_stat[smp_processor_id()].out_slow_mc++; rt_cache_stat[smp_processor_id()].out_slow_mc++;
...@@ -1962,7 +1960,7 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1962,7 +1960,7 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
struct in_device *in_dev = in_dev_get(dev_out); struct in_device *in_dev = in_dev_get(dev_out);
if (in_dev) { if (in_dev) {
if (IN_DEV_MFORWARD(in_dev) && if (IN_DEV_MFORWARD(in_dev) &&
!LOCAL_MCAST(oldkey->dst)) { !LOCAL_MCAST(oldflp->fl4_dst)) {
rth->u.dst.input = ip_mr_input; rth->u.dst.input = ip_mr_input;
rth->u.dst.output = ip_mc_output; rth->u.dst.output = ip_mc_output;
} }
...@@ -1976,7 +1974,7 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey) ...@@ -1976,7 +1974,7 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
rth->rt_flags = flags; rth->rt_flags = flags;
hash = rt_hash_code(oldkey->dst, oldkey->src ^ (oldkey->oif << 5), tos); hash = rt_hash_code(oldflp->fl4_dst, oldflp->fl4_src ^ (oldflp->oif << 5), tos);
err = rt_intern_hash(hash, rth, rp); err = rt_intern_hash(hash, rth, rp);
done: done:
if (free_res) if (free_res)
...@@ -1993,23 +1991,23 @@ out: return err; ...@@ -1993,23 +1991,23 @@ out: return err;
goto done; goto done;
} }
int ip_route_output_key(struct rtable **rp, const struct rt_key *key) int ip_route_output_key(struct rtable **rp, const struct flowi *flp)
{ {
unsigned hash; unsigned hash;
struct rtable *rth; struct rtable *rth;
hash = rt_hash_code(key->dst, key->src ^ (key->oif << 5), key->tos); hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5), flp->fl4_tos);
read_lock_bh(&rt_hash_table[hash].lock); read_lock_bh(&rt_hash_table[hash].lock);
for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) {
if (rth->key.dst == key->dst && if (rth->fl.fl4_dst == flp->fl4_dst &&
rth->key.src == key->src && rth->fl.fl4_src == flp->fl4_src &&
rth->key.iif == 0 && rth->fl.iif == 0 &&
rth->key.oif == key->oif && rth->fl.oif == flp->oif &&
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark == key->fwmark && rth->fl.fl4_fwmark == flp->fl4_fwmark &&
#endif #endif
!((rth->key.tos ^ key->tos) & !((rth->fl.fl4_tos ^ flp->fl4_tos) &
(IPTOS_RT_MASK | RTO_ONLINK))) { (IPTOS_RT_MASK | RTO_ONLINK))) {
rth->u.dst.lastuse = jiffies; rth->u.dst.lastuse = jiffies;
dst_hold(&rth->u.dst); dst_hold(&rth->u.dst);
...@@ -2022,7 +2020,7 @@ int ip_route_output_key(struct rtable **rp, const struct rt_key *key) ...@@ -2022,7 +2020,7 @@ int ip_route_output_key(struct rtable **rp, const struct rt_key *key)
} }
read_unlock_bh(&rt_hash_table[hash].lock); read_unlock_bh(&rt_hash_table[hash].lock);
return ip_route_output_slow(rp, key); return ip_route_output_slow(rp, flp);
} }
static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
...@@ -2042,7 +2040,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, ...@@ -2042,7 +2040,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
r->rtm_family = AF_INET; r->rtm_family = AF_INET;
r->rtm_dst_len = 32; r->rtm_dst_len = 32;
r->rtm_src_len = 0; r->rtm_src_len = 0;
r->rtm_tos = rt->key.tos; r->rtm_tos = rt->fl.fl4_tos;
r->rtm_table = RT_TABLE_MAIN; r->rtm_table = RT_TABLE_MAIN;
r->rtm_type = rt->rt_type; r->rtm_type = rt->rt_type;
r->rtm_scope = RT_SCOPE_UNIVERSE; r->rtm_scope = RT_SCOPE_UNIVERSE;
...@@ -2051,9 +2049,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, ...@@ -2051,9 +2049,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
if (rt->rt_flags & RTCF_NOTIFY) if (rt->rt_flags & RTCF_NOTIFY)
r->rtm_flags |= RTM_F_NOTIFY; r->rtm_flags |= RTM_F_NOTIFY;
RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst); RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
if (rt->key.src) { if (rt->fl.fl4_src) {
r->rtm_src_len = 32; r->rtm_src_len = 32;
RTA_PUT(skb, RTA_SRC, 4, &rt->key.src); RTA_PUT(skb, RTA_SRC, 4, &rt->fl.fl4_src);
} }
if (rt->u.dst.dev) if (rt->u.dst.dev)
RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
...@@ -2061,9 +2059,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, ...@@ -2061,9 +2059,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
if (rt->u.dst.tclassid) if (rt->u.dst.tclassid)
RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid); RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid);
#endif #endif
if (rt->key.iif) if (rt->fl.iif)
RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
else if (rt->rt_src != rt->key.src) else if (rt->rt_src != rt->fl.fl4_src)
RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src);
if (rt->rt_dst != rt->rt_gateway) if (rt->rt_dst != rt->rt_gateway)
RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway); RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
...@@ -2089,7 +2087,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, ...@@ -2089,7 +2087,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
eptr = (struct rtattr*)skb->tail; eptr = (struct rtattr*)skb->tail;
#endif #endif
RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
if (rt->key.iif) { if (rt->fl.iif) {
#ifdef CONFIG_IP_MROUTE #ifdef CONFIG_IP_MROUTE
u32 dst = rt->rt_dst; u32 dst = rt->rt_dst;
...@@ -2109,7 +2107,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, ...@@ -2109,7 +2107,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
} }
} else } else
#endif #endif
RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->key.iif); RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif);
} }
nlh->nlmsg_len = skb->tail - b; nlh->nlmsg_len = skb->tail - b;
...@@ -2163,10 +2161,14 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) ...@@ -2163,10 +2161,14 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
if (!err && rt->u.dst.error) if (!err && rt->u.dst.error)
err = -rt->u.dst.error; err = -rt->u.dst.error;
} else { } else {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
.saddr = src,
.tos = rtm->rtm_tos } } };
int oif = 0; int oif = 0;
if (rta[RTA_OIF - 1]) if (rta[RTA_OIF - 1])
memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
err = ip_route_output(&rt, dst, src, rtm->rtm_tos, oif); fl.oif = oif;
err = ip_route_output_key(&rt, &fl);
} }
if (err) { if (err) {
kfree_skb(skb); kfree_skb(skb);
......
...@@ -171,14 +171,17 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, ...@@ -171,14 +171,17 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
* hasn't changed since we received the original syn, but I see * hasn't changed since we received the original syn, but I see
* no easy way to do this. * no easy way to do this.
*/ */
if (ip_route_output(&rt, {
opt && struct flowi fl = { .nl_u = { .ip4_u =
opt->srr ? opt->faddr : req->af.v4_req.rmt_addr, { .daddr = ((opt && opt->srr) ?
req->af.v4_req.loc_addr, opt->faddr :
RT_CONN_FLAGS(sk), req->af.v4_req.rmt_addr),
0)) { .saddr = req->af.v4_req.loc_addr,
tcp_openreq_free(req); .tos = RT_CONN_FLAGS(sk) } } };
goto out; if (ip_route_output_key(&rt, &fl)) {
tcp_openreq_free(req);
goto out;
}
} }
/* Try to redo what tcp_v4_send_synack did. */ /* Try to redo what tcp_v4_send_synack did. */
......
...@@ -1266,11 +1266,15 @@ static struct dst_entry* tcp_v4_route_req(struct sock *sk, ...@@ -1266,11 +1266,15 @@ static struct dst_entry* tcp_v4_route_req(struct sock *sk,
{ {
struct rtable *rt; struct rtable *rt;
struct ip_options *opt = req->af.v4_req.opt; struct ip_options *opt = req->af.v4_req.opt;
struct flowi fl = { .nl_u = { .ip4_u =
if (ip_route_output(&rt, ((opt && opt->srr) ? opt->faddr : { .daddr = ((opt && opt->srr) ?
req->af.v4_req.rmt_addr), opt->faddr :
req->af.v4_req.loc_addr, req->af.v4_req.rmt_addr),
RT_CONN_FLAGS(sk), sk->bound_dev_if)) { .saddr = req->af.v4_req.loc_addr,
.tos = RT_CONN_FLAGS(sk) } },
.oif = sk->bound_dev_if };
if (ip_route_output_key(&rt, &fl)) {
IP_INC_STATS_BH(IpOutNoRoutes); IP_INC_STATS_BH(IpOutNoRoutes);
return NULL; return NULL;
} }
...@@ -1909,8 +1913,15 @@ int tcp_v4_rebuild_header(struct sock *sk) ...@@ -1909,8 +1913,15 @@ int tcp_v4_rebuild_header(struct sock *sk)
if (inet->opt && inet->opt->srr) if (inet->opt && inet->opt->srr)
daddr = inet->opt->faddr; daddr = inet->opt->faddr;
err = ip_route_output(&rt, daddr, inet->saddr, {
RT_CONN_FLAGS(sk), sk->bound_dev_if); struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = inet->saddr,
.tos = RT_CONN_FLAGS(sk) } },
.oif = sk->bound_dev_if };
err = ip_route_output_key(&rt, &fl);
}
if (!err) { if (!err) {
__sk_dst_set(sk, &rt->u.dst); __sk_dst_set(sk, &rt->u.dst);
tcp_v4_setup_caps(sk, &rt->u.dst); tcp_v4_setup_caps(sk, &rt->u.dst);
......
...@@ -528,7 +528,12 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) ...@@ -528,7 +528,12 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
rt = (struct rtable*)sk_dst_check(sk, 0); rt = (struct rtable*)sk_dst_check(sk, 0);
if (rt == NULL) { if (rt == NULL) {
err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif); struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = ufh.saddr,
.tos = tos } },
.oif = ipc.oif };
err = ip_route_output_key(&rt, &fl);
if (err) if (err)
goto out; goto out;
......
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
# IPv6 configuration # IPv6 configuration
# #
#bool ' IPv6: flow policy support' CONFIG_RT6_POLICY
#bool ' IPv6: firewall support' CONFIG_IPV6_FIREWALL
if [ "$CONFIG_NETFILTER" != "n" ]; then if [ "$CONFIG_NETFILTER" != "n" ]; then
source net/ipv6/netfilter/Config.in source net/ipv6/netfilter/Config.in
fi fi
...@@ -12,7 +12,6 @@ ipv6-objs := af_inet6.o ip6_output.o ip6_input.o addrconf.o sit.o \ ...@@ -12,7 +12,6 @@ ipv6-objs := af_inet6.o ip6_output.o ip6_input.o addrconf.o sit.o \
exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \ exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
ip6_flowlabel.o ipv6_syms.o ip6_flowlabel.o ipv6_syms.o
#obj-$(CONFIG_IPV6_FIREWALL) += ip6_fw.o
obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_NETFILTER) += netfilter/
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -452,7 +452,6 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt) ...@@ -452,7 +452,6 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt)
*/ */
if ((iter->rt6i_dev == rt->rt6i_dev) && if ((iter->rt6i_dev == rt->rt6i_dev) &&
(iter->rt6i_flowr == rt->rt6i_flowr) &&
(ipv6_addr_cmp(&iter->rt6i_gateway, (ipv6_addr_cmp(&iter->rt6i_gateway,
&rt->rt6i_gateway) == 0)) { &rt->rt6i_gateway) == 0)) {
if (!(iter->rt6i_flags&RTF_EXPIRES)) if (!(iter->rt6i_flags&RTF_EXPIRES))
......
/*
* IPv6 Firewall
* Linux INET6 implementation
*
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
* $Id: ip6_fw.c,v 1.16 2001/10/31 08:17:58 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/route.h>
#include <linux/netdevice.h>
#include <linux/in6.h>
#include <linux/udp.h>
#include <linux/init.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/ip6_fw.h>
#include <net/netlink.h>
static unsigned long ip6_fw_rule_cnt;
static struct ip6_fw_rule ip6_fw_rule_list = {
{0},
NULL, NULL,
{0},
IP6_FW_REJECT
};
static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args);
struct flow_rule_ops ip6_fw_ops = {
ip6_fw_accept
};
static struct rt6_info ip6_fw_null_entry = {
{{NULL, 0, 0, NULL,
0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL,
ip6_pkt_discard, ip6_pkt_discard, NULL}},
NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0UL,
0, &ip6_fw_rule_list, {{{{0}}}, 128}, {{{{0}}}, 128}
};
static struct fib6_node ip6_fw_fib = {
NULL, NULL, NULL, NULL,
&ip6_fw_null_entry,
0, RTN_ROOT|RTN_TL_ROOT, 0
};
rwlock_t ip6_fw_lock = RW_LOCK_UNLOCKED;
static void ip6_rule_add(struct ip6_fw_rule *rl)
{
struct ip6_fw_rule *next;
write_lock_bh(&ip6_fw_lock);
ip6_fw_rule_cnt++;
next = &ip6_fw_rule_list;
rl->next = next;
rl->prev = next->prev;
rl->prev->next = rl;
next->prev = rl;
write_unlock_bh(&ip6_fw_lock);
}
static void ip6_rule_del(struct ip6_fw_rule *rl)
{
struct ip6_fw_rule *next, *prev;
write_lock_bh(&ip6_fw_lock);
ip6_fw_rule_cnt--;
next = rl->next;
prev = rl->prev;
next->prev = prev;
prev->next = next;
write_unlock_bh(&ip6_fw_lock);
}
static __inline__ struct ip6_fw_rule * ip6_fwrule_alloc(void)
{
struct ip6_fw_rule *rl;
rl = kmalloc(sizeof(struct ip6_fw_rule), GFP_ATOMIC);
if (rl)
{
memset(rl, 0, sizeof(struct ip6_fw_rule));
rl->flowr.ops = &ip6_fw_ops;
}
return rl;
}
static __inline__ void ip6_fwrule_free(struct ip6_fw_rule * rl)
{
kfree(rl);
}
static __inline__ int port_match(int rl_port, int fl_port)
{
int res = 0;
if (rl_port == 0 || (rl_port == fl_port))
res = 1;
return res;
}
static int ip6_fw_accept_trans(struct ip6_fw_rule *rl,
struct fl_acc_args *args)
{
int res = FLOWR_NODECISION;
int proto = 0;
int sport = 0;
int dport = 0;
switch (args->type) {
case FL_ARG_FORWARD:
{
struct sk_buff *skb = args->fl_u.skb;
struct ipv6hdr *hdr = skb->nh.ipv6h;
int len;
len = skb->len - sizeof(struct ipv6hdr);
proto = hdr->nexthdr;
switch (proto) {
case IPPROTO_TCP:
{
struct tcphdr *th;
if (len < sizeof(struct tcphdr)) {
res = FLOWR_ERROR;
goto out;
}
th = (struct tcphdr *)(hdr + 1);
sport = th->source;
dport = th->dest;
break;
}
case IPPROTO_UDP:
{
struct udphdr *uh;
if (len < sizeof(struct udphdr)) {
res = FLOWR_ERROR;
goto out;
}
uh = (struct udphdr *)(hdr + 1);
sport = uh->source;
dport = uh->dest;
break;
}
default:
goto out;
};
break;
}
case FL_ARG_ORIGIN:
{
proto = args->fl_u.fl_o.flow->proto;
if (proto == IPPROTO_ICMPV6) {
goto out;
} else {
sport = args->fl_u.fl_o.flow->uli_u.ports.sport;
dport = args->fl_u.fl_o.flow->uli_u.ports.dport;
}
break;
}
if (proto == rl->info.proto &&
port_match(args->fl_u.fl_o.flow->uli_u.ports.sport, sport) &&
port_match(args->fl_u.fl_o.flow->uli_u.ports.dport, dport)) {
if (rl->policy & IP6_FW_REJECT)
res = FLOWR_SELECT;
else
res = FLOWR_CLEAR;
}
default:
#if IP6_FW_DEBUG >= 1
printk(KERN_DEBUG "ip6_fw_accept: unknown arg type\n");
#endif
goto out;
};
out:
return res;
}
static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args)
{
struct rt6_info *rt;
struct ip6_fw_rule *rl;
int proto;
int res = FLOWR_NODECISION;
rt = (struct rt6_info *) dst;
rl = (struct ip6_fw_rule *) rt->rt6i_flowr;
proto = rl->info.proto;
switch (proto) {
case 0:
if (rl->policy & IP6_FW_REJECT)
res = FLOWR_SELECT;
else
res = FLOWR_CLEAR;
break;
case IPPROTO_TCP:
case IPPROTO_UDP:
res = ip6_fw_accept_trans(rl, args);
break;
case IPPROTO_ICMPV6:
};
return res;
}
static struct dst_entry * ip6_fw_dup(struct dst_entry *frule,
struct dst_entry *rt,
struct fl_acc_args *args)
{
struct ip6_fw_rule *rl;
struct rt6_info *nrt;
struct rt6_info *frt;
frt = (struct rt6_info *) frule;
rl = (struct ip6_fw_rule *) frt->rt6i_flowr;
nrt = ip6_rt_copy((struct rt6_info *) rt);
if (nrt) {
nrt->u.dst.input = frule->input;
nrt->u.dst.output = frule->output;
nrt->rt6i_flowr = flow_clone(frt->rt6i_flowr);
nrt->rt6i_flags |= RTF_CACHE;
nrt->rt6i_tstamp = jiffies;
}
return (struct dst_entry *) nrt;
}
int ip6_fw_reject(struct sk_buff *skb)
{
#if IP6_FW_DEBUG >= 1
printk(KERN_DEBUG "packet rejected: \n");
#endif
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0,
skb->dev);
/*
* send it via netlink, as (rule, skb)
*/
kfree_skb(skb);
return 0;
}
int ip6_fw_discard(struct sk_buff *skb)
{
printk(KERN_DEBUG "ip6_fw: BUG fw_reject called\n");
kfree_skb(skb);
return 0;
}
int ip6_fw_msg_add(struct ip6_fw_msg *msg)
{
struct in6_rtmsg rtmsg;
struct ip6_fw_rule *rl;
struct rt6_info *rt;
int err;
ipv6_addr_copy(&rtmsg.rtmsg_dst, &msg->dst);
ipv6_addr_copy(&rtmsg.rtmsg_src, &msg->src);
rtmsg.rtmsg_dst_len = msg->dst_len;
rtmsg.rtmsg_src_len = msg->src_len;
rtmsg.rtmsg_metric = IP6_RT_PRIO_FW;
rl = ip6_fwrule_alloc();
if (rl == NULL)
return -ENOMEM;
rl->policy = msg->policy;
rl->info.proto = msg->proto;
rl->info.uli_u.data = msg->u.data;
rtmsg.rtmsg_flags = RTF_NONEXTHOP|RTF_POLICY;
err = ip6_route_add(&rtmsg);
if (err) {
ip6_fwrule_free(rl);
return err;
}
/* The rest will not work for now. --ABK (989725) */
#ifndef notdef
ip6_fwrule_free(rl);
return -EPERM;
#else
rt->u.dst.error = -EPERM;
if (msg->policy == IP6_FW_ACCEPT) {
/*
* Accept rules are never selected
* (i.e. packets use normal forwarding)
*/
rt->u.dst.input = ip6_fw_discard;
rt->u.dst.output = ip6_fw_discard;
} else {
rt->u.dst.input = ip6_fw_reject;
rt->u.dst.output = ip6_fw_reject;
}
ip6_rule_add(rl);
rt->rt6i_flowr = flow_clone((struct flow_rule *)rl);
return 0;
#endif
}
static int ip6_fw_msgrcv(int unit, struct sk_buff *skb)
{
int count = 0;
while (skb->len) {
struct ip6_fw_msg *msg;
if (skb->len < sizeof(struct ip6_fw_msg)) {
count = -EINVAL;
break;
}
msg = (struct ip6_fw_msg *) skb->data;
skb_pull(skb, sizeof(struct ip6_fw_msg));
count += sizeof(struct ip6_fw_msg);
switch (msg->action) {
case IP6_FW_MSG_ADD:
ip6_fw_msg_add(msg);
break;
case IP6_FW_MSG_DEL:
break;
default:
return -EINVAL;
};
}
return count;
}
static void ip6_fw_destroy(struct flow_rule *rl)
{
ip6_fwrule_free((struct ip6_fw_rule *)rl);
}
#ifdef MODULE
#define ip6_fw_init module_init
#endif
void __init ip6_fw_init(void)
{
netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
}
#ifdef MODULE
void cleanup_module(void)
{
netlink_detach(NETLINK_IP6_FW);
}
#endif
...@@ -56,8 +56,6 @@ ...@@ -56,8 +56,6 @@
#include <linux/sysctl.h> #include <linux/sysctl.h>
#endif #endif
#undef CONFIG_RT6_POLICY
/* Set to 3 to get tracing. */ /* Set to 3 to get tracing. */
#define RT6_DEBUG 2 #define RT6_DEBUG 2
...@@ -103,16 +101,22 @@ static struct dst_ops ip6_dst_ops = { ...@@ -103,16 +101,22 @@ static struct dst_ops ip6_dst_ops = {
}; };
struct rt6_info ip6_null_entry = { struct rt6_info ip6_null_entry = {
{{NULL, ATOMIC_INIT(1), 1, &loopback_dev, .u = {
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, .dst = {
-ENETUNREACH, NULL, NULL, .__refcnt = ATOMIC_INIT(1),
ip6_pkt_discard, ip6_pkt_discard, .__use = 1,
#ifdef CONFIG_NET_CLS_ROUTE .dev = &loopback_dev,
0, .obsolete = -1,
#endif .error = -ENETUNREACH,
&ip6_dst_ops}}, .input = ip6_pkt_discard,
NULL, {{{0}}}, RTF_REJECT|RTF_NONEXTHOP, ~0U, .output = ip6_pkt_discard,
255, ATOMIC_INIT(1), {NULL}, {{{{0}}}, 0}, {{{{0}}}, 0} .ops = &ip6_dst_ops
}
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
.rt6i_metric = ~(u32) 0,
.rt6i_hoplimit = 255,
.rt6i_ref = ATOMIC_INIT(1),
}; };
struct fib6_node ip6_routing_table = { struct fib6_node ip6_routing_table = {
...@@ -121,24 +125,6 @@ struct fib6_node ip6_routing_table = { ...@@ -121,24 +125,6 @@ struct fib6_node ip6_routing_table = {
0, RTN_ROOT|RTN_TL_ROOT|RTN_RTINFO, 0 0, RTN_ROOT|RTN_TL_ROOT|RTN_RTINFO, 0
}; };
#ifdef CONFIG_RT6_POLICY
int ip6_rt_policy = 0;
struct pol_chain *rt6_pol_list = NULL;
static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb);
static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk);
static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt,
struct in6_addr *daddr,
struct in6_addr *saddr,
struct fl_acc_args *args);
#else
#define ip6_rt_policy (0)
#endif
/* Protects all the ip6 fib */ /* Protects all the ip6 fib */
rwlock_t rt6_lock = RW_LOCK_UNLOCKED; rwlock_t rt6_lock = RW_LOCK_UNLOCKED;
...@@ -386,38 +372,6 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, ...@@ -386,38 +372,6 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
return &ip6_null_entry; return &ip6_null_entry;
} }
#ifdef CONFIG_RT6_POLICY
static __inline__ struct rt6_info *rt6_flow_lookup_in(struct rt6_info *rt,
struct sk_buff *skb)
{
struct in6_addr *daddr, *saddr;
struct fl_acc_args arg;
arg.type = FL_ARG_FORWARD;
arg.fl_u.skb = skb;
saddr = &skb->nh.ipv6h->saddr;
daddr = &skb->nh.ipv6h->daddr;
return rt6_flow_lookup(rt, daddr, saddr, &arg);
}
static __inline__ struct rt6_info *rt6_flow_lookup_out(struct rt6_info *rt,
struct sock *sk,
struct flowi *fl)
{
struct fl_acc_args arg;
arg.type = FL_ARG_ORIGIN;
arg.fl_u.fl_o.sk = sk;
arg.fl_u.fl_o.flow = fl;
return rt6_flow_lookup(rt, fl->nl_u.ip6_u.daddr, fl->nl_u.ip6_u.saddr,
&arg);
}
#endif
#define BACKTRACK() \ #define BACKTRACK() \
if (rt == &ip6_null_entry && strict) { \ if (rt == &ip6_null_entry && strict) { \
while ((fn = fn->parent) != NULL) { \ while ((fn = fn->parent) != NULL) { \
...@@ -450,53 +404,29 @@ void ip6_route_input(struct sk_buff *skb) ...@@ -450,53 +404,29 @@ void ip6_route_input(struct sk_buff *skb)
rt = fn->leaf; rt = fn->leaf;
if ((rt->rt6i_flags & RTF_CACHE)) { if ((rt->rt6i_flags & RTF_CACHE)) {
if (ip6_rt_policy == 0) { rt = rt6_device_match(rt, skb->dev->ifindex, strict);
rt = rt6_device_match(rt, skb->dev->ifindex, strict); BACKTRACK();
BACKTRACK(); dst_clone(&rt->u.dst);
dst_clone(&rt->u.dst); goto out;
goto out;
}
#ifdef CONFIG_RT6_POLICY
if ((rt->rt6i_flags & RTF_FLOW)) {
struct rt6_info *sprt;
for (sprt = rt; sprt; sprt = sprt->u.next) {
if (rt6_flow_match_in(sprt, skb)) {
rt = sprt;
dst_clone(&rt->u.dst);
goto out;
}
}
}
#endif
} }
rt = rt6_device_match(rt, skb->dev->ifindex, 0); rt = rt6_device_match(rt, skb->dev->ifindex, 0);
BACKTRACK(); BACKTRACK();
if (ip6_rt_policy == 0) { if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { read_unlock_bh(&rt6_lock);
read_unlock_bh(&rt6_lock);
rt = rt6_cow(rt, &skb->nh.ipv6h->daddr, rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
&skb->nh.ipv6h->saddr); &skb->nh.ipv6h->saddr);
if (rt->u.dst.error != -EEXIST || --attempts <= 0) if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2; goto out2;
/* Race condition! In the gap, when rt6_lock was /* Race condition! In the gap, when rt6_lock was
released someone could insert this route. Relookup. released someone could insert this route. Relookup.
*/ */
goto relookup; goto relookup;
}
dst_clone(&rt->u.dst);
} else {
#ifdef CONFIG_RT6_POLICY
rt = rt6_flow_lookup_in(rt, skb);
#else
/* NEVER REACHED */
#endif
} }
dst_clone(&rt->u.dst);
out: out:
read_unlock_bh(&rt6_lock); read_unlock_bh(&rt6_lock);
...@@ -525,26 +455,10 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) ...@@ -525,26 +455,10 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
rt = fn->leaf; rt = fn->leaf;
if ((rt->rt6i_flags & RTF_CACHE)) { if ((rt->rt6i_flags & RTF_CACHE)) {
if (ip6_rt_policy == 0) { rt = rt6_device_match(rt, fl->oif, strict);
rt = rt6_device_match(rt, fl->oif, strict); BACKTRACK();
BACKTRACK(); dst_clone(&rt->u.dst);
dst_clone(&rt->u.dst); goto out;
goto out;
}
#ifdef CONFIG_RT6_POLICY
if ((rt->rt6i_flags & RTF_FLOW)) {
struct rt6_info *sprt;
for (sprt = rt; sprt; sprt = sprt->u.next) {
if (rt6_flow_match_out(sprt, sk)) {
rt = sprt;
dst_clone(&rt->u.dst);
goto out;
}
}
}
#endif
} }
if (rt->rt6i_flags & RTF_DEFAULT) { if (rt->rt6i_flags & RTF_DEFAULT) {
if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF) if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
...@@ -554,29 +468,21 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) ...@@ -554,29 +468,21 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
BACKTRACK(); BACKTRACK();
} }
if (ip6_rt_policy == 0) { if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { read_unlock_bh(&rt6_lock);
read_unlock_bh(&rt6_lock);
rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr, rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
fl->nl_u.ip6_u.saddr); fl->nl_u.ip6_u.saddr);
if (rt->u.dst.error != -EEXIST || --attempts <= 0) if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2; goto out2;
/* Race condition! In the gap, when rt6_lock was /* Race condition! In the gap, when rt6_lock was
released someone could insert this route. Relookup. released someone could insert this route. Relookup.
*/ */
goto relookup; goto relookup;
}
dst_clone(&rt->u.dst);
} else {
#ifdef CONFIG_RT6_POLICY
rt = rt6_flow_lookup_out(rt, sk, fl);
#else
/* NEVER REACHED */
#endif
} }
dst_clone(&rt->u.dst);
out: out:
read_unlock_bh(&rt6_lock); read_unlock_bh(&rt6_lock);
...@@ -1304,121 +1210,6 @@ int ip6_rt_addr_del(struct in6_addr *addr, struct net_device *dev) ...@@ -1304,121 +1210,6 @@ int ip6_rt_addr_del(struct in6_addr *addr, struct net_device *dev)
return err; return err;
} }
#ifdef CONFIG_RT6_POLICY
static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb)
{
struct flow_filter *frule;
struct pkt_filter *filter;
int res = 1;
if ((frule = rt->rt6i_filter) == NULL)
goto out;
if (frule->type != FLR_INPUT) {
res = 0;
goto out;
}
for (filter = frule->u.filter; filter; filter = filter->next) {
__u32 *word;
word = (__u32 *) skb->h.raw;
word += filter->offset;
if ((*word ^ filter->value) & filter->mask) {
res = 0;
break;
}
}
out:
return res;
}
static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk)
{
struct flow_filter *frule;
int res = 1;
if ((frule = rt->rt6i_filter) == NULL)
goto out;
if (frule->type != FLR_INPUT) {
res = 0;
goto out;
}
if (frule->u.sk != sk)
res = 0;
out:
return res;
}
static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt,
struct in6_addr *daddr,
struct in6_addr *saddr,
struct fl_acc_args *args)
{
struct flow_rule *frule;
struct rt6_info *nrt = NULL;
struct pol_chain *pol;
for (pol = rt6_pol_list; pol; pol = pol->next) {
struct fib6_node *fn;
struct rt6_info *sprt;
fn = fib6_lookup(pol->rules, daddr, saddr);
do {
for (sprt = fn->leaf; sprt; sprt=sprt->u.next) {
int res;
frule = sprt->rt6i_flowr;
#if RT6_DEBUG >= 2
if (frule == NULL) {
printk(KERN_DEBUG "NULL flowr\n");
goto error;
}
#endif
res = frule->ops->accept(rt, sprt, args, &nrt);
switch (res) {
case FLOWR_SELECT:
goto found;
case FLOWR_CLEAR:
goto next_policy;
case FLOWR_NODECISION:
break;
default:
goto error;
};
}
fn = fn->parent;
} while ((fn->fn_flags & RTN_TL_ROOT) == 0);
next_policy:
}
error:
dst_clone(&ip6_null_entry.u.dst);
return &ip6_null_entry;
found:
if (nrt == NULL)
goto error;
nrt->rt6i_flags |= RTF_CACHE;
dst_clone(&nrt->u.dst);
err = rt6_ins(nrt);
if (err)
nrt->u.dst.error = err;
return nrt;
}
#endif
static int fib6_ifdown(struct rt6_info *rt, void *arg) static int fib6_ifdown(struct rt6_info *rt, void *arg)
{ {
if (((void*)rt->rt6i_dev == arg || arg == NULL) && if (((void*)rt->rt6i_dev == arg || arg == NULL) &&
......
...@@ -502,9 +502,16 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -502,9 +502,16 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
dst = addr6->s6_addr32[3]; dst = addr6->s6_addr32[3];
} }
if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) { {
tunnel->stat.tx_carrier_errors++; struct flowi fl = { .nl_u = { .ip4_u =
goto tx_error_icmp; { .daddr = dst,
.saddr = tiph->saddr,
.tos = RT_TOS(tos) } },
.oif = tunnel->parms.link };
if (ip_route_output_key(&rt, &fl)) {
tunnel->stat.tx_carrier_errors++;
goto tx_error_icmp;
}
} }
if (rt->rt_type != RTN_UNICAST) { if (rt->rt_type != RTN_UNICAST) {
tunnel->stat.tx_carrier_errors++; tunnel->stat.tx_carrier_errors++;
...@@ -777,8 +784,13 @@ static int ipip6_tunnel_init(struct net_device *dev) ...@@ -777,8 +784,13 @@ static int ipip6_tunnel_init(struct net_device *dev)
ipip6_tunnel_init_gen(dev); ipip6_tunnel_init_gen(dev);
if (iph->daddr) { if (iph->daddr) {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = iph->daddr,
.saddr = iph->saddr,
.tos = RT_TOS(iph->tos) } },
.oif = tunnel->parms.link };
struct rtable *rt; struct rtable *rt;
if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) { if (!ip_route_output_key(&rt, &fl)) {
tdev = rt->u.dst.dev; tdev = rt->u.dst.dev;
ip_rt_put(rt); ip_rt_put(rt);
} }
......
...@@ -154,7 +154,7 @@ static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp, ...@@ -154,7 +154,7 @@ static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp,
if (head == NULL) if (head == NULL)
goto old_method; goto old_method;
iif = ((struct rtable*)dst)->key.iif; iif = ((struct rtable*)dst)->fl.iif;
h = route4_fastmap_hash(id, iif); h = route4_fastmap_hash(id, iif);
if (id == head->fastmap[h].id && if (id == head->fastmap[h].id &&
......
...@@ -260,16 +260,10 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) ...@@ -260,16 +260,10 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address)
{ {
int dst_mtu = SCTP_DEFAULT_MAXSEGMENT; int dst_mtu = SCTP_DEFAULT_MAXSEGMENT;
struct rtable *rt; struct rtable *rt;
struct rt_key key = { struct flowi fl = { .nl_u = { .ip4_u =
.dst = address->v4.sin_addr.s_addr, { .daddr = address->v4.sin_addr.s_addr } } };
.src = 0,
.iif = 0, if (ip_route_output_key(&rt, &fl)) {
.oif = 0,
.tos = 0,
.scope = 0
};
if (ip_route_output_key(&rt, &key)) {
SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key" SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key"
" failed, returning %d as dst_mtu\n", " failed, returning %d as dst_mtu\n",
dst_mtu); dst_mtu);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment