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 @@
#define _NET_FLOW_H
struct flowi {
int proto; /* {TCP, UDP, ICMP} */
int oif;
int iif;
union {
struct {
__u32 daddr;
__u32 saddr;
__u32 fwmark;
__u8 tos;
__u8 scope;
} ip4_u;
struct {
......@@ -27,9 +31,12 @@ struct flowi {
#define fl6_flowlabel nl_u.ip6_u.flowlabel
#define fl4_dst nl_u.ip4_u.daddr
#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 {
struct {
__u16 sport;
......@@ -41,61 +48,8 @@ struct flowi {
__u8 code;
} icmpt;
unsigned long data;
__u32 spi;
} 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
......@@ -70,14 +70,6 @@ struct rt6_info
u8 rt6i_hoplimit;
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_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 @@
#define _NET_IP_FIB_H
#include <linux/config.h>
#include <net/flow.h>
struct kern_rta
{
......@@ -117,7 +118,7 @@ struct fib_table
{
unsigned char tb_id;
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,
struct kern_rta *rta, struct nlmsghdr *n,
struct netlink_skb_parms *req);
......@@ -130,7 +131,7 @@ struct fib_table
int (*tb_get_info)(struct fib_table *table, char *buf,
int first, int count);
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];
};
......@@ -152,18 +153,18 @@ static inline struct fib_table *fib_new_table(int 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) &&
main_table->tb_lookup(main_table, key, res))
if (local_table->tb_lookup(local_table, flp, res) &&
main_table->tb_lookup(main_table, flp, res))
return -ENETUNREACH;
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)
main_table->tb_select_default(main_table, key, res);
main_table->tb_select_default(main_table, flp, res);
}
#else /* CONFIG_IP_MULTIPLE_TABLES */
......@@ -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])
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 void fib_rule_put(struct fib_rule *r);
......@@ -191,7 +192,7 @@ static inline struct fib_table *fib_new_table(int 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 */
......@@ -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 fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
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 */
extern int ip_fib_check_default(u32 gw, struct net_device *dev);
extern void fib_release_info(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,
const struct nlmsghdr *, int *err);
extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *, struct kern_rta *rta, struct fib_info *fi);
......
......@@ -27,6 +27,7 @@
#include <linux/config.h>
#include <net/dst.h>
#include <net/inetpeer.h>
#include <net/flow.h>
#include <linux/in_route.h>
#include <linux/rtnetlink.h>
#include <linux/route.h>
......@@ -45,19 +46,6 @@
#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 rtable
{
......@@ -78,7 +66,7 @@ struct rtable
__u32 rt_gateway;
/* Cache lookup keys */
struct rt_key key;
struct flowi fl;
/* Miscellaneous cached information */
__u32 rt_spec_dst; /* RFC1122 specific destination */
......@@ -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);
extern void ip_rt_advice(struct rtable **rp, int advice);
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 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);
......@@ -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 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)
{
if (rt)
......@@ -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)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
.saddr = src,
.tos = tos } },
.oif = oif };
int err;
err = ip_route_output(rp, dst, src, tos, oif);
err = ip_route_output_key(rp, &fl);
if (err || (dst && src))
return err;
dst = (*rp)->rt_dst;
src = (*rp)->rt_src;
fl.fl4_dst = (*rp)->rt_dst;
fl.fl4_src = (*rp)->rt_src;
ip_rt_put(*rp);
*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);
......
......@@ -509,6 +509,7 @@ int clip_setentry(struct atm_vcc *vcc,u32 ip)
struct atmarp_entry *entry;
int error;
struct clip_vcc *clip_vcc;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = 1 } } };
struct rtable *rt;
if (vcc->push != clip_push) {
......@@ -525,7 +526,7 @@ int clip_setentry(struct atm_vcc *vcc,u32 ip)
unlink_clip_vcc(clip_vcc);
return 0;
}
error = ip_route_output(&rt,ip,0,1,0);
error = ip_route_output_key(&rt,&fl);
if (error) return error;
neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1);
ip_rt_put(rt);
......
......@@ -563,13 +563,15 @@ int ip_route_me_harder(struct sk_buff **pskb)
{
struct iphdr *iph = (*pskb)->nh.iph;
struct rtable *rt;
struct rt_key key = { dst:iph->daddr,
src:iph->saddr,
oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
tos:RT_TOS(iph->tos)|RTO_CONN,
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = iph->daddr,
.saddr = iph->saddr,
.tos = RT_TOS(iph->tos)|RTO_CONN,
#ifdef CONFIG_IP_ROUTE_FWMARK
fwmark:(*pskb)->nfmark
.fwmark = (*pskb)->nfmark
#endif
} },
.oif = (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
};
struct net_device *dev_src = NULL;
int err;
......@@ -578,10 +580,10 @@ int ip_route_me_harder(struct sk_buff **pskb)
0 or a local address; however some non-standard hacks like
ipt_REJECT.c:send_reset() can cause packets with foreign
saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */
if(key.src && !(dev_src = ip_dev_find(key.src)))
key.src = 0;
if(fl.fl4_src && !(dev_src = ip_dev_find(fl.fl4_src)))
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",
NIPQUAD(iph->daddr), NIPQUAD(iph->saddr),
(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
......
......@@ -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)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip,
.saddr = tip } } };
struct rtable *rt;
int flag = 0;
/*unsigned long now; */
if (ip_route_output(&rt, sip, tip, 0, 0) < 0)
if (ip_route_output_key(&rt, &fl) < 0)
return 1;
if (rt->u.dst.dev != dev) {
NET_INC_STATS_BH(ArpFilter);
......@@ -890,8 +892,10 @@ int arp_req_set(struct arpreq *r, struct net_device * dev)
if (r->arp_flags & ATF_PERM)
r->arp_flags |= ATF_COM;
if (dev == NULL) {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
.tos = RTO_ONLINK } } };
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;
dev = rt->u.dst.dev;
ip_rt_put(rt);
......@@ -974,8 +978,10 @@ int arp_req_delete(struct arpreq *r, struct net_device * dev)
}
if (dev == NULL) {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
.tos = RTO_ONLINK } } };
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;
dev = rt->u.dst.dev;
ip_rt_put(rt);
......
......@@ -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 rt_key key;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res;
struct net_device *dev = NULL;
memset(&key, 0, sizeof(key));
key.dst = addr;
#ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL;
#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;
}
if (res.type != RTN_LOCAL)
......@@ -170,7 +168,7 @@ struct net_device * ip_dev_find(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;
unsigned ret = RTN_BROADCAST;
......@@ -179,15 +177,13 @@ unsigned inet_addr_type(u32 addr)
if (MULTICAST(addr))
return RTN_MULTICAST;
memset(&key, 0, sizeof(key));
key.dst = addr;
#ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL;
#endif
if (local_table) {
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;
fib_res_put(&res);
}
......@@ -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 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;
int no_addr, rpf;
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;
read_lock(&inetdev_lock);
in_dev = __in_dev_get(dev);
......@@ -231,7 +224,7 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
if (in_dev == NULL)
goto e_inval;
if (fib_lookup(&key, &res))
if (fib_lookup(&fl, &res))
goto last_resort;
if (res.type != RTN_UNICAST)
goto e_inval_res;
......@@ -252,10 +245,10 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
goto last_resort;
if (rpf)
goto e_inval;
key.oif = dev->ifindex;
fl.oif = dev->ifindex;
ret = 0;
if (fib_lookup(&key, &res) == 0) {
if (fib_lookup(&fl, &res) == 0) {
if (res.type == RTN_UNICAST) {
*spec_dst = FIB_RES_PREFSRC(res);
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
......
......@@ -266,7 +266,7 @@ fn_new_zone(struct fn_hash *table, int z)
}
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;
struct fn_zone *fz;
......@@ -275,7 +275,7 @@ fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result
read_lock(&fib_hash_lock);
for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
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) {
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
continue;
}
#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;
#endif
f->fn_state |= FN_S_ACCESSED;
if (f->fn_state&FN_S_ZOMBIE)
continue;
if (f->fn_scope < key->scope)
if (f->fn_scope < flp->fl4_scope)
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) {
res->type = f->fn_type;
res->scope = f->fn_scope;
......@@ -338,7 +338,7 @@ static int fib_detect_death(struct fib_info *fi, int order,
}
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;
struct fib_node *f;
......
......@@ -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;
struct fib_rule *r, *policy;
struct fib_table *tb;
u32 daddr = key->dst;
u32 saddr = key->src;
u32 daddr = flp->fl4_dst;
u32 saddr = flp->fl4_src;
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);
for (r = fib_rules; r; r=r->r_next) {
if (((saddr^r->r_src) & r->r_srcmask) ||
((daddr^r->r_dst) & r->r_dstmask) ||
#ifdef CONFIG_IP_ROUTE_TOS
(r->r_tos && r->r_tos != key->tos) ||
(r->r_tos && r->r_tos != flp->fl4_tos) ||
#endif
#ifdef CONFIG_IP_ROUTE_FWMARK
(r->r_fwmark && r->r_fwmark != key->fwmark) ||
(r->r_fwmark && r->r_fwmark != flp->fl4_fwmark) ||
#endif
(r->r_ifindex && r->r_ifindex != key->iif))
(r->r_ifindex && r->r_ifindex != flp->iif))
continue;
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)
continue;
err = tb->tb_lookup(tb, key, res);
err = tb->tb_lookup(tb, flp, res);
if (err == 0) {
res->r = policy;
if (policy)
......@@ -369,13 +369,13 @@ FRprintk("FAILURE\n");
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 &&
FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
struct fib_table *tb;
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
int err;
if (nh->nh_gw) {
struct rt_key key;
struct fib_result res;
#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
nh->nh_scope = RT_SCOPE_LINK;
return 0;
}
memset(&key, 0, sizeof(key));
key.dst = nh->nh_gw;
key.oif = nh->nh_oif;
key.scope = r->rtm_scope + 1;
/* It is not necessary, but requires a bit of thinking */
if (key.scope < RT_SCOPE_LINK)
key.scope = RT_SCOPE_LINK;
if ((err = fib_lookup(&key, &res)) != 0)
return err;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = nh->nh_gw,
.scope = r->rtm_scope + 1 } },
.oif = nh->nh_oif };
/* It is not necessary, but requires a bit of thinking */
if (fl.fl4_scope < RT_SCOPE_LINK)
fl.fl4_scope = RT_SCOPE_LINK;
if ((err = fib_lookup(&fl, &res)) != 0)
return err;
}
err = -EINVAL;
if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
goto out;
......@@ -578,7 +579,7 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
}
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;
......@@ -603,7 +604,7 @@ fib_semantic_match(int type, struct fib_info *fi, const struct rt_key *key, stru
for_nexthops(fi) {
if (nh->nh_flags&RTNH_F_DEAD)
continue;
if (!key->oif || key->oif == nh->nh_oif)
if (!flp->oif || flp->oif == nh->nh_oif)
break;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
......@@ -949,7 +950,7 @@ int fib_sync_up(struct net_device *dev)
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;
int w;
......
......@@ -418,9 +418,14 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
if (ipc.opt->srr)
daddr = icmp_param->replyopts.faddr;
}
if (ip_route_output(&rt, daddr, rt->rt_spec_dst,
RT_TOS(skb->nh.iph->tos), 0))
goto out_unlock;
{
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))
goto out_unlock;
}
if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
icmp_param->data.icmph.code)) {
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)
* Restore original addresses if packet has been translated.
*/
if (rt->rt_flags & RTCF_NAT && IPCB(skb_in)->flags & IPSKB_TRANSLATED) {
iph->daddr = rt->key.dst;
iph->saddr = rt->key.src;
iph->daddr = rt->fl.fl4_dst;
iph->saddr = rt->fl.fl4_src;
}
#endif
......@@ -539,9 +544,13 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
IPTOS_PREC_INTERNETCONTROL) :
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))
goto ende;
......@@ -563,9 +572,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
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);
if (ip_route_output(&rt, icmp_param.replyopts.faddr,
saddr, RT_TOS(tos), 0))
if (ip_route_output_key(&rt, &fl))
goto out_unlock;
}
......
......@@ -207,8 +207,12 @@ static int igmp_send_report(struct net_device *dev, u32 group, int type)
if (type == IGMP_HOST_LEAVE_MESSAGE)
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) {
ip_rt_put(rt);
return -1;
......@@ -374,7 +378,7 @@ int igmp_rcv(struct sk_buff *skb)
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
/* Is it our report looped back? */
if (((struct rtable*)skb->dst)->key.iif == 0)
if (((struct rtable*)skb->dst)->fl.iif == 0)
break;
igmp_heard_report(in_dev, ih->group);
break;
......@@ -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)
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = imr->imr_address.s_addr } } };
struct rtable *rt;
struct net_device *dev = NULL;
struct in_device *idev = NULL;
......@@ -619,7 +625,7 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
__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;
ip_rt_put(rt);
}
......
......@@ -412,6 +412,7 @@ void ipgre_err(struct sk_buff *skb, u32 info)
u16 flags;
int grehlen = (iph->ihl<<2) + 4;
struct sk_buff *skb2;
struct flowi fl;
struct rtable *rt;
if (p[1] != htons(ETH_P_IP))
......@@ -488,7 +489,10 @@ void ipgre_err(struct sk_buff *skb, u32 info)
skb2->nh.raw = skb2->data;
/* 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);
return;
}
......@@ -498,7 +502,10 @@ void ipgre_err(struct sk_buff *skb, u32 info)
if (rt->rt_flags&RTCF_LOCAL) {
ip_rt_put(rt);
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) {
ip_rt_put(rt);
kfree_skb(skb2);
......@@ -619,7 +626,7 @@ int ipgre_rcv(struct sk_buff *skb)
#ifdef CONFIG_NET_IPGRE_BROADCAST
if (MULTICAST(iph->daddr)) {
/* Looped back packet, drop it! */
if (((struct rtable*)skb->dst)->key.iif == 0)
if (((struct rtable*)skb->dst)->fl.iif == 0)
goto drop;
tunnel->stat.multicast++;
skb->pkt_type = PACKET_BROADCAST;
......@@ -749,9 +756,16 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
tos &= ~1;
}
if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
tunnel->stat.tx_carrier_errors++;
goto tx_error;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .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;
......@@ -1104,10 +1118,13 @@ static int ipgre_open(struct net_device *dev)
MOD_INC_USE_COUNT;
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;
if (ip_route_output(&rt, t->parms.iph.daddr,
t->parms.iph.saddr, RT_TOS(t->parms.iph.tos),
t->parms.link)) {
if (ip_route_output_key(&rt, &fl)) {
MOD_DEC_USE_COUNT;
return -EADDRNOTAVAIL;
}
......@@ -1177,8 +1194,13 @@ static int ipgre_tunnel_init(struct net_device *dev)
/* Guess output device to choose reasonable mtu and hard_header_len */
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;
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;
ip_rt_put(rt);
}
......
......@@ -117,23 +117,21 @@ ip_do_nat(struct sk_buff *skb)
if (rt->rt_flags&RTCF_SNAT) {
if (ciph->daddr != osaddr) {
struct fib_result res;
struct rt_key key;
unsigned flags = 0;
key.src = ciph->daddr;
key.dst = ciph->saddr;
key.iif = skb->dev->ifindex;
key.oif = 0;
struct flowi fl = { .nl_u =
{ .ip4_u =
{ .daddr = ciph->saddr,
.saddr = ciph->daddr,
#ifdef CONFIG_IP_ROUTE_TOS
key.tos = RT_TOS(ciph->tos);
#endif
#ifdef CONFIG_IP_ROUTE_FWMARK
key.fwmark = 0;
.tos = RT_TOS(ciph->tos)
#endif
} },
.iif = skb->dev->ifindex };
/* Use fib_lookup() until we get our own
* hash table of NATed hosts -- Rani
*/
if (fib_lookup(&key, &res) == 0) {
if (fib_lookup(&fl, &res) == 0) {
if (res.r) {
ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
if (ciph->daddr != idaddr)
......
......@@ -372,14 +372,20 @@ int ip_queue_xmit(struct sk_buff *skb)
if(opt && opt->srr)
daddr = opt->faddr;
/* If this fails, retransmit mechanism of transport layer will
* keep trying until route appears or the connection times itself
* out.
*/
if (ip_route_output(&rt, daddr, inet->saddr,
RT_CONN_FLAGS(sk),
sk->bound_dev_if))
goto no_route;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = inet->saddr,
.tos = RT_CONN_FLAGS(sk) } },
.oif = sk->bound_dev_if };
/* 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);
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
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.
......
......@@ -355,6 +355,7 @@ void ipip_err(struct sk_buff *skb, u32 info)
int rel_code = 0;
int rel_info = 0;
struct sk_buff *skb2;
struct flowi fl;
struct rtable *rt;
if (len < hlen + sizeof(struct iphdr))
......@@ -417,7 +418,10 @@ void ipip_err(struct sk_buff *skb, u32 info)
skb2->nh.raw = skb2->data;
/* 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);
return;
}
......@@ -427,7 +431,10 @@ void ipip_err(struct sk_buff *skb, u32 info)
if (rt->rt_flags&RTCF_LOCAL) {
ip_rt_put(rt);
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) {
ip_rt_put(rt);
kfree_skb(skb2);
......@@ -560,9 +567,16 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_error_icmp;
}
if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
tunnel->stat.tx_carrier_errors++;
goto tx_error_icmp;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .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;
......@@ -822,8 +836,13 @@ static int ipip_tunnel_init(struct net_device *dev)
ipip_tunnel_init_gen(dev);
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;
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;
ip_rt_put(rt);
}
......
......@@ -1146,11 +1146,20 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c,
#endif
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;
encap = sizeof(struct iphdr);
} 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;
}
......@@ -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) {
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.
Very complicated situation...
......
......@@ -68,12 +68,13 @@ do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
/* Setup the masquerade, if not already */
if (!info->initialized) {
u_int32_t newsrc;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->daddr } } };
struct rtable *rt;
struct ip_nat_multi_range range;
/* Pass 0 instead of saddr, since it's going to be changed
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");
return NF_DROP;
}
......
......@@ -209,10 +209,11 @@ find_appropriate_src(const struct ip_conntrack_tuple *tuple,
static int
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;
/* 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",
NIPQUAD(var_ip));
return 0;
......
......@@ -69,7 +69,6 @@ masquerade_target(struct sk_buff **pskb,
struct ip_nat_multi_range newrange;
u_int32_t newsrc;
struct rtable *rt;
struct rt_key key;
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
......@@ -84,17 +83,21 @@ masquerade_target(struct sk_buff **pskb,
mr = targinfo;
key.dst = (*pskb)->nh.iph->daddr;
key.src = 0; /* Unknown: that's what we're trying to establish */
key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
key.oif = out->ifindex;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = (*pskb)->nh.iph->daddr,
.tos = (RT_TOS((*pskb)->nh.iph->tos) |
RTO_CONN),
#ifdef CONFIG_IP_ROUTE_FWMARK
key.fwmark = (*pskb)->nfmark;
.fwmark = (*pskb)->nfmark
#endif
if (ip_route_output_key(&rt, &key) != 0) {
/* Shouldn't happen */
printk("MASQUERADE: No route: Rusty's brain broke!\n");
return NF_DROP;
} },
.oif = out->ifindex };
if (ip_route_output_key(&rt, &fl) != 0) {
/* Shouldn't happen */
printk("MASQUERADE: No route: Rusty's brain broke!\n");
return NF_DROP;
}
}
newsrc = rt->rt_src;
......
......@@ -44,12 +44,13 @@ struct in_device;
static int route_mirror(struct sk_buff *skb)
{
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;
/* Backwards */
if (ip_route_output(&rt, iph->saddr, iph->daddr,
RT_TOS(iph->tos) | RTO_CONN,
0)) {
if (ip_route_output_key(&rt, &fl)) {
return 0;
}
......
......@@ -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->ihl);
/* Routing: if not headed for us, route won't like source */
if (ip_route_output(&rt, nskb->nh.iph->daddr,
local ? nskb->nh.iph->saddr : 0,
RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
0) != 0)
goto free_nskb;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = nskb->nh.iph->daddr,
.saddr = (local ?
nskb->nh.iph->saddr :
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);
nskb->dst = &rt->u.dst;
......@@ -207,9 +214,14 @@ static void send_unreach(struct sk_buff *skb_in, int code)
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. */
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)
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)
goto done;
......
......@@ -251,7 +251,7 @@ static int rt_cache_get_info(char *buffer, char **start, off_t offset,
(int)r->u.dst.advmss + 40,
r->u.dst.window,
(int)((r->u.dst.rtt >> 3) + r->u.dst.rttvar),
r->key.tos,
r->fl.fl4_tos,
r->u.dst.hh ?
atomic_read(&r->u.dst.hh->hh_refcnt) :
-1,
......@@ -332,7 +332,7 @@ static __inline__ int rt_fast_clean(struct rtable *rth)
/* Kill broadcast/multicast entries very aggresively, if they
collide in hash table with more useful entries */
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)
......@@ -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);
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 */
*rthp = rth->u.rt_next;
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)
/* Try to bind route to arp only if it is output
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);
if (err) {
write_unlock_bh(&rt_hash_table[hash].lock);
......@@ -806,11 +806,11 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
while ((rth = *rthp) != NULL) {
struct rtable *rt;
if (rth->key.dst != daddr ||
rth->key.src != skeys[i] ||
rth->key.tos != tos ||
rth->key.oif != ikeys[k] ||
rth->key.iif != 0) {
if (rth->fl.fl4_dst != daddr ||
rth->fl.fl4_src != skeys[i] ||
rth->fl.fl4_tos != tos ||
rth->fl.oif != ikeys[k] ||
rth->fl.iif != 0) {
rthp = &rth->u.rt_next;
continue;
}
......@@ -901,14 +901,14 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
ret = NULL;
} else if ((rt->rt_flags & RTCF_REDIRECTED) ||
rt->u.dst.expires) {
unsigned hash = rt_hash_code(rt->key.dst,
rt->key.src ^
(rt->key.oif << 5),
rt->key.tos);
unsigned hash = rt_hash_code(rt->fl.fl4_dst,
rt->fl.fl4_src ^
(rt->fl.oif << 5),
rt->fl.fl4_tos);
#if RT_CACHE_DEBUG >= 1
printk(KERN_DEBUG "ip_rt_advice: redirect to "
"%u.%u.%u.%u/%02x dropped\n",
NIPQUAD(rt->rt_dst), rt->key.tos);
NIPQUAD(rt->rt_dst), rt->fl.fl4_tos);
#endif
rt_del(hash, rt);
ret = NULL;
......@@ -1052,12 +1052,12 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
read_lock(&rt_hash_table[hash].lock);
for (rth = rt_hash_table[hash].chain; rth;
rth = rth->u.rt_next) {
if (rth->key.dst == daddr &&
rth->key.src == skeys[i] &&
if (rth->fl.fl4_dst == daddr &&
rth->fl.fl4_src == skeys[i] &&
rth->rt_dst == daddr &&
rth->rt_src == iph->saddr &&
rth->key.tos == tos &&
rth->key.iif == 0 &&
rth->fl.fl4_tos == tos &&
rth->fl.iif == 0 &&
!(rth->u.dst.mxlock & (1 << RTAX_MTU))) {
unsigned short mtu = new_mtu;
......@@ -1162,9 +1162,9 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
u32 src;
struct fib_result res;
if (rt->key.iif == 0)
if (rt->fl.iif == 0)
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
if (res.type == RTN_NAT)
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,
atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST;
rth->key.dst = daddr;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->key.tos = tos;
rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark = skb->nfmark;
rth->fl.fl4_fwmark= skb->nfmark;
#endif
rth->key.src = saddr;
rth->fl.fl4_src = saddr;
rth->rt_src = saddr;
#ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = daddr;
......@@ -1279,10 +1279,10 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
rth->u.dst.tclassid = itag;
#endif
rth->rt_iif =
rth->key.iif = dev->ifindex;
rth->fl.iif = dev->ifindex;
rth->u.dst.dev = &loopback_dev;
dev_hold(rth->u.dst.dev);
rth->key.oif = 0;
rth->fl.oif = 0;
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
rth->rt_type = RTN_MULTICAST;
......@@ -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,
u8 tos, struct net_device *dev)
{
struct rt_key key;
struct fib_result res;
struct in_device *in_dev = in_dev_get(dev);
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;
u32 itag = 0;
struct rtable * rth;
......@@ -1341,17 +1350,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
if (!in_dev)
goto out;
key.dst = daddr;
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);
hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos);
/* Check for the most weird martians, which can be not detected
by fib_lookup.
......@@ -1375,7 +1374,7 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
/*
* 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))
goto e_inval;
goto no_route;
......@@ -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);
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);
free_res = 0;
if (fib_lookup(&key, &res))
if (fib_lookup(&fl, &res))
goto e_inval;
free_res = 1;
if (res.type != RTN_UNICAST)
goto e_inval;
flags |= RTCF_DNAT;
}
key.src = src_map;
fl.fl4_src = src_map;
}
#endif
......@@ -1431,8 +1430,8 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
goto martian_destination;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
if (res.fi->fib_nhs > 1 && key.oif == 0)
fib_select_multipath(&key, &res);
if (res.fi->fib_nhs > 1 && fl.oif == 0)
fib_select_multipath(&fl, &res);
#endif
out_dev = in_dev_get(FIB_RES_DEV(res));
if (out_dev == NULL) {
......@@ -1469,26 +1468,26 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST;
rth->key.dst = daddr;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->key.tos = tos;
rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark = skb->nfmark;
rth->fl.fl4_fwmark= skb->nfmark;
#endif
rth->key.src = saddr;
rth->fl.fl4_src = saddr;
rth->rt_src = saddr;
rth->rt_gateway = daddr;
#ifdef CONFIG_IP_ROUTE_NAT
rth->rt_src_map = key.src;
rth->rt_dst_map = key.dst;
rth->rt_src_map = fl.fl4_src;
rth->rt_dst_map = fl.fl4_dst;
if (flags&RTCF_DNAT)
rth->rt_gateway = key.dst;
rth->rt_gateway = fl.fl4_dst;
#endif
rth->rt_iif =
rth->key.iif = dev->ifindex;
rth->fl.iif = dev->ifindex;
rth->u.dst.dev = out_dev->dev;
dev_hold(rth->u.dst.dev);
rth->key.oif = 0;
rth->fl.oif = 0;
rth->rt_spec_dst= spec_dst;
rth->u.dst.input = ip_forward;
......@@ -1546,26 +1545,25 @@ out: return err;
atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST;
rth->key.dst = daddr;
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->key.tos = tos;
rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark = skb->nfmark;
rth->fl.fl4_fwmark= skb->nfmark;
#endif
rth->key.src = saddr;
rth->fl.fl4_src = saddr;
rth->rt_src = saddr;
#ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = key.dst;
rth->rt_src_map = key.src;
rth->rt_dst_map = fl.fl4_dst;
rth->rt_src_map = fl.fl4_src;
#endif
#ifdef CONFIG_NET_CLS_ROUTE
rth->u.dst.tclassid = itag;
#endif
rth->rt_iif =
rth->key.iif = dev->ifindex;
rth->fl.iif = dev->ifindex;
rth->u.dst.dev = &loopback_dev;
dev_hold(rth->u.dst.dev);
rth->key.oif = 0;
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
rth->u.dst.input= ip_local_deliver;
......@@ -1643,14 +1641,14 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
read_lock(&rt_hash_table[hash].lock);
for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) {
if (rth->key.dst == daddr &&
rth->key.src == saddr &&
rth->key.iif == iif &&
rth->key.oif == 0 &&
if (rth->fl.fl4_dst == daddr &&
rth->fl.fl4_src == saddr &&
rth->fl.iif == iif &&
rth->fl.oif == 0 &&
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark == skb->nfmark &&
rth->fl.fl4_fwmark == skb->nfmark &&
#endif
rth->key.tos == tos) {
rth->fl.fl4_tos == tos) {
rth->u.dst.lastuse = jiffies;
dst_hold(&rth->u.dst);
rth->u.dst.__use++;
......@@ -1699,9 +1697,22 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
* 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;
unsigned flags = 0;
struct rtable *rth;
......@@ -1709,33 +1720,21 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
unsigned hash;
int free_res = 0;
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;
#ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL;
#endif
if (oldkey->src) {
if (oldflp->fl4_src) {
err = -EINVAL;
if (MULTICAST(oldkey->src) ||
BADCLASS(oldkey->src) ||
ZERONET(oldkey->src))
if (MULTICAST(oldflp->fl4_src) ||
BADCLASS(oldflp->fl4_src) ||
ZERONET(oldflp->fl4_src))
goto out;
/* 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)
goto out;
......@@ -1747,8 +1746,8 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
of another iface. --ANK
*/
if (oldkey->oif == 0
&& (MULTICAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF)) {
if (oldflp->oif == 0
&& (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF)) {
/* Special hack: user can direct multicasts
and limited broadcast via necessary interface
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)
Luckily, this hack is good workaround.
*/
key.oif = dev_out->ifindex;
fl.oif = dev_out->ifindex;
goto make_route;
}
if (dev_out)
dev_put(dev_out);
dev_out = NULL;
}
if (oldkey->oif) {
dev_out = dev_get_by_index(oldkey->oif);
if (oldflp->oif) {
dev_out = dev_get_by_index(oldflp->oif);
err = -ENODEV;
if (dev_out == NULL)
goto out;
......@@ -1781,39 +1780,39 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
goto out; /* Wrong error code */
}
if (LOCAL_MCAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF) {
if (!key.src)
key.src = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK);
if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF) {
if (!fl.fl4_src)
fl.fl4_src = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK);
goto make_route;
}
if (!key.src) {
if (MULTICAST(oldkey->dst))
key.src = inet_select_addr(dev_out, 0,
key.scope);
else if (!oldkey->dst)
key.src = inet_select_addr(dev_out, 0,
RT_SCOPE_HOST);
if (!fl.fl4_src) {
if (MULTICAST(oldflp->fl4_dst))
fl.fl4_src = inet_select_addr(dev_out, 0,
fl.fl4_scope);
else if (!oldflp->fl4_dst)
fl.fl4_src = inet_select_addr(dev_out, 0,
RT_SCOPE_HOST);
}
}
if (!key.dst) {
key.dst = key.src;
if (!key.dst)
key.dst = key.src = htonl(INADDR_LOOPBACK);
if (!fl.fl4_dst) {
fl.fl4_dst = fl.fl4_src;
if (!fl.fl4_dst)
fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK);
if (dev_out)
dev_put(dev_out);
dev_out = &loopback_dev;
dev_hold(dev_out);
key.oif = loopback_dev.ifindex;
fl.oif = loopback_dev.ifindex;
res.type = RTN_LOCAL;
flags |= RTCF_LOCAL;
goto make_route;
}
if (fib_lookup(&key, &res)) {
if (fib_lookup(&fl, &res)) {
res.fi = NULL;
if (oldkey->oif) {
if (oldflp->oif) {
/* Apparently, routing tables are wrong. Assume,
that the destination is on link.
......@@ -1832,9 +1831,9 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
likely IPv6, but we do not.
*/
if (key.src == 0)
key.src = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK);
if (fl.fl4_src == 0)
fl.fl4_src = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK);
res.type = RTN_UNICAST;
goto make_route;
}
......@@ -1849,13 +1848,13 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
goto e_inval;
if (res.type == RTN_LOCAL) {
if (!key.src)
key.src = key.dst;
if (!fl.fl4_src)
fl.fl4_src = fl.fl4_dst;
if (dev_out)
dev_put(dev_out);
dev_out = &loopback_dev;
dev_hold(dev_out);
key.oif = dev_out->ifindex;
fl.oif = dev_out->ifindex;
if (res.fi)
fib_info_put(res.fi);
res.fi = NULL;
......@@ -1864,31 +1863,31 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
if (res.fi->fib_nhs > 1 && key.oif == 0)
fib_select_multipath(&key, &res);
if (res.fi->fib_nhs > 1 && fl.oif == 0)
fib_select_multipath(&fl, &res);
else
#endif
if (!res.prefixlen && res.type == RTN_UNICAST && !key.oif)
fib_select_default(&key, &res);
if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
fib_select_default(&fl, &res);
if (!key.src)
key.src = FIB_RES_PREFSRC(res);
if (!fl.fl4_src)
fl.fl4_src = FIB_RES_PREFSRC(res);
if (dev_out)
dev_put(dev_out);
dev_out = FIB_RES_DEV(res);
dev_hold(dev_out);
key.oif = dev_out->ifindex;
fl.oif = dev_out->ifindex;
make_route:
if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK))
if (LOOPBACK(fl.fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
goto e_inval;
if (key.dst == 0xFFFFFFFF)
if (fl.fl4_dst == 0xFFFFFFFF)
res.type = RTN_BROADCAST;
else if (MULTICAST(key.dst))
else if (MULTICAST(fl.fl4_dst))
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;
if (dev_out->flags & IFF_LOOPBACK)
......@@ -1904,7 +1903,7 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
flags |= RTCF_MULTICAST|RTCF_LOCAL;
read_lock(&inetdev_lock);
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;
read_unlock(&inetdev_lock);
/* If multicast route do not exist use
......@@ -1923,25 +1922,24 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST;
rth->key.dst = oldkey->dst;
rth->key.tos = tos;
rth->key.src = oldkey->src;
rth->key.iif = 0;
rth->key.oif = oldkey->oif;
rth->fl.fl4_dst = oldflp->fl4_dst;
rth->fl.fl4_tos = tos;
rth->fl.fl4_src = oldflp->fl4_src;
rth->fl.oif = oldflp->oif;
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark = oldkey->fwmark;
rth->fl.fl4_fwmark= oldflp->fl4_fwmark;
#endif
rth->rt_dst = key.dst;
rth->rt_src = key.src;
rth->rt_dst = fl.fl4_dst;
rth->rt_src = fl.fl4_src;
#ifdef CONFIG_IP_ROUTE_NAT
rth->rt_dst_map = key.dst;
rth->rt_src_map = key.src;
rth->rt_dst_map = fl.fl4_dst;
rth->rt_src_map = fl.fl4_src;
#endif
rth->rt_iif = oldkey->oif ? : dev_out->ifindex;
rth->rt_iif = oldflp->oif ? : dev_out->ifindex;
rth->u.dst.dev = dev_out;
dev_hold(dev_out);
rth->rt_gateway = key.dst;
rth->rt_spec_dst= key.src;
rth->rt_gateway = fl.fl4_dst;
rth->rt_spec_dst= fl.fl4_src;
rth->u.dst.output=ip_output;
......@@ -1949,10 +1947,10 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
if (flags & RTCF_LOCAL) {
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)) {
rth->rt_spec_dst = key.src;
rth->rt_spec_dst = fl.fl4_src;
if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) {
rth->u.dst.output = ip_mc_output;
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)
struct in_device *in_dev = in_dev_get(dev_out);
if (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.output = ip_mc_output;
}
......@@ -1976,7 +1974,7 @@ int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
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);
done:
if (free_res)
......@@ -1993,23 +1991,23 @@ out: return err;
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;
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);
for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) {
if (rth->key.dst == key->dst &&
rth->key.src == key->src &&
rth->key.iif == 0 &&
rth->key.oif == key->oif &&
if (rth->fl.fl4_dst == flp->fl4_dst &&
rth->fl.fl4_src == flp->fl4_src &&
rth->fl.iif == 0 &&
rth->fl.oif == flp->oif &&
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->key.fwmark == key->fwmark &&
rth->fl.fl4_fwmark == flp->fl4_fwmark &&
#endif
!((rth->key.tos ^ key->tos) &
!((rth->fl.fl4_tos ^ flp->fl4_tos) &
(IPTOS_RT_MASK | RTO_ONLINK))) {
rth->u.dst.lastuse = jiffies;
dst_hold(&rth->u.dst);
......@@ -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);
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,
......@@ -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_dst_len = 32;
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_type = rt->rt_type;
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,
if (rt->rt_flags & RTCF_NOTIFY)
r->rtm_flags |= RTM_F_NOTIFY;
RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
if (rt->key.src) {
if (rt->fl.fl4_src) {
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)
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,
if (rt->u.dst.tclassid)
RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid);
#endif
if (rt->key.iif)
if (rt->fl.iif)
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);
if (rt->rt_dst != 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,
eptr = (struct rtattr*)skb->tail;
#endif
RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
if (rt->key.iif) {
if (rt->fl.iif) {
#ifdef CONFIG_IP_MROUTE
u32 dst = rt->rt_dst;
......@@ -2109,7 +2107,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
}
} else
#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;
......@@ -2163,10 +2161,14 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
if (!err && rt->u.dst.error)
err = -rt->u.dst.error;
} else {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
.saddr = src,
.tos = rtm->rtm_tos } } };
int oif = 0;
if (rta[RTA_OIF - 1])
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) {
kfree_skb(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
* no easy way to do this.
*/
if (ip_route_output(&rt,
opt &&
opt->srr ? opt->faddr : req->af.v4_req.rmt_addr,
req->af.v4_req.loc_addr,
RT_CONN_FLAGS(sk),
0)) {
tcp_openreq_free(req);
goto out;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = ((opt && opt->srr) ?
opt->faddr :
req->af.v4_req.rmt_addr),
.saddr = req->af.v4_req.loc_addr,
.tos = RT_CONN_FLAGS(sk) } } };
if (ip_route_output_key(&rt, &fl)) {
tcp_openreq_free(req);
goto out;
}
}
/* Try to redo what tcp_v4_send_synack did. */
......
......@@ -1266,11 +1266,15 @@ static struct dst_entry* tcp_v4_route_req(struct sock *sk,
{
struct rtable *rt;
struct ip_options *opt = req->af.v4_req.opt;
if (ip_route_output(&rt, ((opt && opt->srr) ? opt->faddr :
req->af.v4_req.rmt_addr),
req->af.v4_req.loc_addr,
RT_CONN_FLAGS(sk), sk->bound_dev_if)) {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = ((opt && opt->srr) ?
opt->faddr :
req->af.v4_req.rmt_addr),
.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);
return NULL;
}
......@@ -1909,8 +1913,15 @@ int tcp_v4_rebuild_header(struct sock *sk)
if (inet->opt && inet->opt->srr)
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) {
__sk_dst_set(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)
rt = (struct rtable*)sk_dst_check(sk, 0);
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)
goto out;
......
......@@ -2,9 +2,6 @@
# IPv6 configuration
#
#bool ' IPv6: flow policy support' CONFIG_RT6_POLICY
#bool ' IPv6: firewall support' CONFIG_IPV6_FIREWALL
if [ "$CONFIG_NETFILTER" != "n" ]; then
source net/ipv6/netfilter/Config.in
fi
......@@ -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 \
ip6_flowlabel.o ipv6_syms.o
#obj-$(CONFIG_IPV6_FIREWALL) += ip6_fw.o
obj-$(CONFIG_NETFILTER) += netfilter/
include $(TOPDIR)/Rules.make
......@@ -452,7 +452,6 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt)
*/
if ((iter->rt6i_dev == rt->rt6i_dev) &&
(iter->rt6i_flowr == rt->rt6i_flowr) &&
(ipv6_addr_cmp(&iter->rt6i_gateway,
&rt->rt6i_gateway) == 0)) {
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 @@
#include <linux/sysctl.h>
#endif
#undef CONFIG_RT6_POLICY
/* Set to 3 to get tracing. */
#define RT6_DEBUG 2
......@@ -103,16 +101,22 @@ static struct dst_ops ip6_dst_ops = {
};
struct rt6_info ip6_null_entry = {
{{NULL, ATOMIC_INIT(1), 1, &loopback_dev,
-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-ENETUNREACH, NULL, NULL,
ip6_pkt_discard, ip6_pkt_discard,
#ifdef CONFIG_NET_CLS_ROUTE
0,
#endif
&ip6_dst_ops}},
NULL, {{{0}}}, RTF_REJECT|RTF_NONEXTHOP, ~0U,
255, ATOMIC_INIT(1), {NULL}, {{{{0}}}, 0}, {{{{0}}}, 0}
.u = {
.dst = {
.__refcnt = ATOMIC_INIT(1),
.__use = 1,
.dev = &loopback_dev,
.obsolete = -1,
.error = -ENETUNREACH,
.input = ip6_pkt_discard,
.output = ip6_pkt_discard,
.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 = {
......@@ -121,24 +125,6 @@ struct fib6_node ip6_routing_table = {
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 */
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,
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() \
if (rt == &ip6_null_entry && strict) { \
while ((fn = fn->parent) != NULL) { \
......@@ -450,53 +404,29 @@ void ip6_route_input(struct sk_buff *skb)
rt = fn->leaf;
if ((rt->rt6i_flags & RTF_CACHE)) {
if (ip6_rt_policy == 0) {
rt = rt6_device_match(rt, skb->dev->ifindex, strict);
BACKTRACK();
dst_clone(&rt->u.dst);
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, strict);
BACKTRACK();
dst_clone(&rt->u.dst);
goto out;
}
rt = rt6_device_match(rt, skb->dev->ifindex, 0);
BACKTRACK();
if (ip6_rt_policy == 0) {
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
read_unlock_bh(&rt6_lock);
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
read_unlock_bh(&rt6_lock);
rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
&skb->nh.ipv6h->saddr);
rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
&skb->nh.ipv6h->saddr);
if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2;
/* Race condition! In the gap, when rt6_lock was
released someone could insert this route. Relookup.
*/
goto relookup;
}
dst_clone(&rt->u.dst);
} else {
#ifdef CONFIG_RT6_POLICY
rt = rt6_flow_lookup_in(rt, skb);
#else
/* NEVER REACHED */
#endif
if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2;
/* Race condition! In the gap, when rt6_lock was
released someone could insert this route. Relookup.
*/
goto relookup;
}
dst_clone(&rt->u.dst);
out:
read_unlock_bh(&rt6_lock);
......@@ -525,26 +455,10 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
rt = fn->leaf;
if ((rt->rt6i_flags & RTF_CACHE)) {
if (ip6_rt_policy == 0) {
rt = rt6_device_match(rt, fl->oif, strict);
BACKTRACK();
dst_clone(&rt->u.dst);
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
rt = rt6_device_match(rt, fl->oif, strict);
BACKTRACK();
dst_clone(&rt->u.dst);
goto out;
}
if (rt->rt6i_flags & RTF_DEFAULT) {
if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
......@@ -554,29 +468,21 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
BACKTRACK();
}
if (ip6_rt_policy == 0) {
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
read_unlock_bh(&rt6_lock);
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
read_unlock_bh(&rt6_lock);
rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
fl->nl_u.ip6_u.saddr);
rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
fl->nl_u.ip6_u.saddr);
if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2;
if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2;
/* Race condition! In the gap, when rt6_lock was
released someone could insert this route. 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
/* Race condition! In the gap, when rt6_lock was
released someone could insert this route. Relookup.
*/
goto relookup;
}
dst_clone(&rt->u.dst);
out:
read_unlock_bh(&rt6_lock);
......@@ -1304,121 +1210,6 @@ int ip6_rt_addr_del(struct in6_addr *addr, struct net_device *dev)
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)
{
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)
dst = addr6->s6_addr32[3];
}
if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
tunnel->stat.tx_carrier_errors++;
goto tx_error_icmp;
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .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) {
tunnel->stat.tx_carrier_errors++;
......@@ -777,8 +784,13 @@ static int ipip6_tunnel_init(struct net_device *dev)
ipip6_tunnel_init_gen(dev);
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;
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;
ip_rt_put(rt);
}
......
......@@ -154,7 +154,7 @@ static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp,
if (head == NULL)
goto old_method;
iif = ((struct rtable*)dst)->key.iif;
iif = ((struct rtable*)dst)->fl.iif;
h = route4_fastmap_hash(id, iif);
if (id == head->fastmap[h].id &&
......
......@@ -260,16 +260,10 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address)
{
int dst_mtu = SCTP_DEFAULT_MAXSEGMENT;
struct rtable *rt;
struct rt_key key = {
.dst = address->v4.sin_addr.s_addr,
.src = 0,
.iif = 0,
.oif = 0,
.tos = 0,
.scope = 0
};
if (ip_route_output_key(&rt, &key)) {
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = address->v4.sin_addr.s_addr } } };
if (ip_route_output_key(&rt, &fl)) {
SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key"
" failed, returning %d as dst_mtu\n",
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