mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1699 commits) bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL. vlan: Calling vlan_hwaccel_do_receive() is always valid. tproxy: use the interface primary IP address as a default value for --on-ip tproxy: added IPv6 support to the socket match cxgb3: function namespace cleanup tproxy: added IPv6 support to the TPROXY target tproxy: added IPv6 socket lookup function to nf_tproxy_core be2net: Changes to use only priority codes allowed by f/w tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled tproxy: added tproxy sockopt interface in the IPV6 layer tproxy: added udp6_lib_lookup function tproxy: added const specifiers to udp lookup functions tproxy: split off ipv6 defragmentation to a separate module l2tp: small cleanup nf_nat: restrict ICMP translation for embedded header can: mcp251x: fix generation of error frames can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set can-raw: add msg_flags to distinguish local traffic 9p: client code cleanup rds: make local functions/variables static ... Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and drivers/net/wireless/ath/ath9k/debug.c as per David
This commit is contained in:
commit
5f05647dd8
1341 changed files with 157282 additions and 84033 deletions
|
|
@ -215,9 +215,15 @@ config NET_IPIP
|
|||
be inserted in and removed from the running kernel whenever you
|
||||
want). Most people won't need this and can say N.
|
||||
|
||||
config NET_IPGRE_DEMUX
|
||||
tristate "IP: GRE demultiplexer"
|
||||
help
|
||||
This is helper module to demultiplex GRE packets on GRE version field criteria.
|
||||
Required by ip_gre and pptp modules.
|
||||
|
||||
config NET_IPGRE
|
||||
tristate "IP: GRE tunnels over IP"
|
||||
depends on IPV6 || IPV6=n
|
||||
depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX
|
||||
help
|
||||
Tunneling means encapsulating data of one protocol type within
|
||||
another protocol and sending it over a channel that understands the
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
|
|||
obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
|
||||
obj-$(CONFIG_IP_MROUTE) += ipmr.o
|
||||
obj-$(CONFIG_NET_IPIP) += ipip.o
|
||||
obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
|
||||
obj-$(CONFIG_NET_IPGRE) += ip_gre.o
|
||||
obj-$(CONFIG_SYN_COOKIES) += syncookies.o
|
||||
obj-$(CONFIG_INET_AH) += ah4.o
|
||||
|
|
|
|||
|
|
@ -227,18 +227,16 @@ EXPORT_SYMBOL(inet_ehash_secret);
|
|||
|
||||
/*
|
||||
* inet_ehash_secret must be set exactly once
|
||||
* Instead of using a dedicated spinlock, we (ab)use inetsw_lock
|
||||
*/
|
||||
void build_ehash_secret(void)
|
||||
{
|
||||
u32 rnd;
|
||||
|
||||
do {
|
||||
get_random_bytes(&rnd, sizeof(rnd));
|
||||
} while (rnd == 0);
|
||||
spin_lock_bh(&inetsw_lock);
|
||||
if (!inet_ehash_secret)
|
||||
inet_ehash_secret = rnd;
|
||||
spin_unlock_bh(&inetsw_lock);
|
||||
|
||||
cmpxchg(&inet_ehash_secret, 0, rnd);
|
||||
}
|
||||
EXPORT_SYMBOL(build_ehash_secret);
|
||||
|
||||
|
|
|
|||
245
net/ipv4/arp.c
245
net/ipv4/arp.c
|
|
@ -55,7 +55,7 @@
|
|||
* Stuart Cheshire : Metricom and grat arp fixes
|
||||
* *** FOR 2.1 clean this up ***
|
||||
* Lawrence V. Stefani: (08/12/96) Added FDDI support.
|
||||
* Alan Cox : Took the AP1000 nasty FDDI hack and
|
||||
* Alan Cox : Took the AP1000 nasty FDDI hack and
|
||||
* folded into the mainstream FDDI code.
|
||||
* Ack spit, Linus how did you allow that
|
||||
* one in...
|
||||
|
|
@ -120,14 +120,14 @@ EXPORT_SYMBOL(clip_tbl_hook);
|
|||
#endif
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/netfilter_arp.h>
|
||||
|
||||
/*
|
||||
* Interface to generic neighbour cache.
|
||||
*/
|
||||
static u32 arp_hash(const void *pkey, const struct net_device *dev);
|
||||
static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 rnd);
|
||||
static int arp_constructor(struct neighbour *neigh);
|
||||
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb);
|
||||
static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
|
||||
|
|
@ -161,7 +161,7 @@ static const struct neigh_ops arp_direct_ops = {
|
|||
.queue_xmit = dev_queue_xmit,
|
||||
};
|
||||
|
||||
const struct neigh_ops arp_broken_ops = {
|
||||
static const struct neigh_ops arp_broken_ops = {
|
||||
.family = AF_INET,
|
||||
.solicit = arp_solicit,
|
||||
.error_report = arp_error_report,
|
||||
|
|
@ -170,35 +170,34 @@ const struct neigh_ops arp_broken_ops = {
|
|||
.hh_output = dev_queue_xmit,
|
||||
.queue_xmit = dev_queue_xmit,
|
||||
};
|
||||
EXPORT_SYMBOL(arp_broken_ops);
|
||||
|
||||
struct neigh_table arp_tbl = {
|
||||
.family = AF_INET,
|
||||
.entry_size = sizeof(struct neighbour) + 4,
|
||||
.key_len = 4,
|
||||
.hash = arp_hash,
|
||||
.constructor = arp_constructor,
|
||||
.proxy_redo = parp_redo,
|
||||
.id = "arp_cache",
|
||||
.parms = {
|
||||
.tbl = &arp_tbl,
|
||||
.base_reachable_time = 30 * HZ,
|
||||
.retrans_time = 1 * HZ,
|
||||
.gc_staletime = 60 * HZ,
|
||||
.reachable_time = 30 * HZ,
|
||||
.delay_probe_time = 5 * HZ,
|
||||
.queue_len = 3,
|
||||
.ucast_probes = 3,
|
||||
.mcast_probes = 3,
|
||||
.anycast_delay = 1 * HZ,
|
||||
.proxy_delay = (8 * HZ) / 10,
|
||||
.proxy_qlen = 64,
|
||||
.locktime = 1 * HZ,
|
||||
.family = AF_INET,
|
||||
.entry_size = sizeof(struct neighbour) + 4,
|
||||
.key_len = 4,
|
||||
.hash = arp_hash,
|
||||
.constructor = arp_constructor,
|
||||
.proxy_redo = parp_redo,
|
||||
.id = "arp_cache",
|
||||
.parms = {
|
||||
.tbl = &arp_tbl,
|
||||
.base_reachable_time = 30 * HZ,
|
||||
.retrans_time = 1 * HZ,
|
||||
.gc_staletime = 60 * HZ,
|
||||
.reachable_time = 30 * HZ,
|
||||
.delay_probe_time = 5 * HZ,
|
||||
.queue_len = 3,
|
||||
.ucast_probes = 3,
|
||||
.mcast_probes = 3,
|
||||
.anycast_delay = 1 * HZ,
|
||||
.proxy_delay = (8 * HZ) / 10,
|
||||
.proxy_qlen = 64,
|
||||
.locktime = 1 * HZ,
|
||||
},
|
||||
.gc_interval = 30 * HZ,
|
||||
.gc_thresh1 = 128,
|
||||
.gc_thresh2 = 512,
|
||||
.gc_thresh3 = 1024,
|
||||
.gc_interval = 30 * HZ,
|
||||
.gc_thresh1 = 128,
|
||||
.gc_thresh2 = 512,
|
||||
.gc_thresh3 = 1024,
|
||||
};
|
||||
EXPORT_SYMBOL(arp_tbl);
|
||||
|
||||
|
|
@ -226,14 +225,16 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
|
|||
}
|
||||
|
||||
|
||||
static u32 arp_hash(const void *pkey, const struct net_device *dev)
|
||||
static u32 arp_hash(const void *pkey,
|
||||
const struct net_device *dev,
|
||||
__u32 hash_rnd)
|
||||
{
|
||||
return jhash_2words(*(u32 *)pkey, dev->ifindex, arp_tbl.hash_rnd);
|
||||
return jhash_2words(*(u32 *)pkey, dev->ifindex, hash_rnd);
|
||||
}
|
||||
|
||||
static int arp_constructor(struct neighbour *neigh)
|
||||
{
|
||||
__be32 addr = *(__be32*)neigh->primary_key;
|
||||
__be32 addr = *(__be32 *)neigh->primary_key;
|
||||
struct net_device *dev = neigh->dev;
|
||||
struct in_device *in_dev;
|
||||
struct neigh_parms *parms;
|
||||
|
|
@ -296,16 +297,19 @@ static int arp_constructor(struct neighbour *neigh)
|
|||
neigh->ops = &arp_broken_ops;
|
||||
neigh->output = neigh->ops->output;
|
||||
return 0;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
;}
|
||||
}
|
||||
#endif
|
||||
if (neigh->type == RTN_MULTICAST) {
|
||||
neigh->nud_state = NUD_NOARP;
|
||||
arp_mc_map(addr, neigh->ha, dev, 1);
|
||||
} else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
|
||||
} else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) {
|
||||
neigh->nud_state = NUD_NOARP;
|
||||
memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
|
||||
} else if (neigh->type == RTN_BROADCAST || dev->flags&IFF_POINTOPOINT) {
|
||||
} else if (neigh->type == RTN_BROADCAST ||
|
||||
(dev->flags & IFF_POINTOPOINT)) {
|
||||
neigh->nud_state = NUD_NOARP;
|
||||
memcpy(neigh->ha, dev->broadcast, dev->addr_len);
|
||||
}
|
||||
|
|
@ -315,7 +319,7 @@ static int arp_constructor(struct neighbour *neigh)
|
|||
else
|
||||
neigh->ops = &arp_generic_ops;
|
||||
|
||||
if (neigh->nud_state&NUD_VALID)
|
||||
if (neigh->nud_state & NUD_VALID)
|
||||
neigh->output = neigh->ops->connected_output;
|
||||
else
|
||||
neigh->output = neigh->ops->output;
|
||||
|
|
@ -334,7 +338,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
|||
__be32 saddr = 0;
|
||||
u8 *dst_ha = NULL;
|
||||
struct net_device *dev = neigh->dev;
|
||||
__be32 target = *(__be32*)neigh->primary_key;
|
||||
__be32 target = *(__be32 *)neigh->primary_key;
|
||||
int probes = atomic_read(&neigh->probes);
|
||||
struct in_device *in_dev;
|
||||
|
||||
|
|
@ -347,7 +351,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
|||
switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
|
||||
default:
|
||||
case 0: /* By default announce any local IP */
|
||||
if (skb && inet_addr_type(dev_net(dev), ip_hdr(skb)->saddr) == RTN_LOCAL)
|
||||
if (skb && inet_addr_type(dev_net(dev),
|
||||
ip_hdr(skb)->saddr) == RTN_LOCAL)
|
||||
saddr = ip_hdr(skb)->saddr;
|
||||
break;
|
||||
case 1: /* Restrict announcements of saddr in same subnet */
|
||||
|
|
@ -369,16 +374,21 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
|||
if (!saddr)
|
||||
saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
|
||||
|
||||
if ((probes -= neigh->parms->ucast_probes) < 0) {
|
||||
if (!(neigh->nud_state&NUD_VALID))
|
||||
printk(KERN_DEBUG "trying to ucast probe in NUD_INVALID\n");
|
||||
probes -= neigh->parms->ucast_probes;
|
||||
if (probes < 0) {
|
||||
if (!(neigh->nud_state & NUD_VALID))
|
||||
printk(KERN_DEBUG
|
||||
"trying to ucast probe in NUD_INVALID\n");
|
||||
dst_ha = neigh->ha;
|
||||
read_lock_bh(&neigh->lock);
|
||||
} else if ((probes -= neigh->parms->app_probes) < 0) {
|
||||
} else {
|
||||
probes -= neigh->parms->app_probes;
|
||||
if (probes < 0) {
|
||||
#ifdef CONFIG_ARPD
|
||||
neigh_app_ns(neigh);
|
||||
neigh_app_ns(neigh);
|
||||
#endif
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
|
||||
|
|
@ -451,7 +461,8 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
|
|||
* is allowed to use this function, it is scheduled to be removed. --ANK
|
||||
*/
|
||||
|
||||
static int arp_set_predefined(int addr_hint, unsigned char * haddr, __be32 paddr, struct net_device * dev)
|
||||
static int arp_set_predefined(int addr_hint, unsigned char *haddr,
|
||||
__be32 paddr, struct net_device *dev)
|
||||
{
|
||||
switch (addr_hint) {
|
||||
case RTN_LOCAL:
|
||||
|
|
@ -483,17 +494,16 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
|
|||
|
||||
paddr = skb_rtable(skb)->rt_gateway;
|
||||
|
||||
if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev))
|
||||
if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr,
|
||||
paddr, dev))
|
||||
return 0;
|
||||
|
||||
n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);
|
||||
|
||||
if (n) {
|
||||
n->used = jiffies;
|
||||
if (n->nud_state&NUD_VALID || neigh_event_send(n, skb) == 0) {
|
||||
read_lock_bh(&n->lock);
|
||||
memcpy(haddr, n->ha, dev->addr_len);
|
||||
read_unlock_bh(&n->lock);
|
||||
if (n->nud_state & NUD_VALID || neigh_event_send(n, skb) == 0) {
|
||||
neigh_ha_snapshot(haddr, n, dev);
|
||||
neigh_release(n);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -515,13 +525,14 @@ int arp_bind_neighbour(struct dst_entry *dst)
|
|||
return -EINVAL;
|
||||
if (n == NULL) {
|
||||
__be32 nexthop = ((struct rtable *)dst)->rt_gateway;
|
||||
if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
|
||||
if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
|
||||
nexthop = 0;
|
||||
n = __neigh_lookup_errno(
|
||||
#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
|
||||
dev->type == ARPHRD_ATM ? clip_tbl_hook :
|
||||
dev->type == ARPHRD_ATM ?
|
||||
clip_tbl_hook :
|
||||
#endif
|
||||
&arp_tbl, &nexthop, dev);
|
||||
&arp_tbl, &nexthop, dev);
|
||||
if (IS_ERR(n))
|
||||
return PTR_ERR(n);
|
||||
dst->neighbour = n;
|
||||
|
|
@ -543,8 +554,8 @@ static inline int arp_fwd_proxy(struct in_device *in_dev,
|
|||
|
||||
if (!IN_DEV_PROXY_ARP(in_dev))
|
||||
return 0;
|
||||
|
||||
if ((imi = IN_DEV_MEDIUM_ID(in_dev)) == 0)
|
||||
imi = IN_DEV_MEDIUM_ID(in_dev);
|
||||
if (imi == 0)
|
||||
return 1;
|
||||
if (imi == -1)
|
||||
return 0;
|
||||
|
|
@ -555,7 +566,7 @@ static inline int arp_fwd_proxy(struct in_device *in_dev,
|
|||
if (out_dev)
|
||||
omi = IN_DEV_MEDIUM_ID(out_dev);
|
||||
|
||||
return (omi != imi && omi != -1);
|
||||
return omi != imi && omi != -1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -685,7 +696,7 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
|
|||
arp->ar_pln = 4;
|
||||
arp->ar_op = htons(type);
|
||||
|
||||
arp_ptr=(unsigned char *)(arp+1);
|
||||
arp_ptr = (unsigned char *)(arp + 1);
|
||||
|
||||
memcpy(arp_ptr, src_hw, dev->addr_len);
|
||||
arp_ptr += dev->addr_len;
|
||||
|
|
@ -735,9 +746,8 @@ void arp_send(int type, int ptype, __be32 dest_ip,
|
|||
|
||||
skb = arp_create(type, ptype, dest_ip, dev, src_ip,
|
||||
dest_hw, src_hw, target_hw);
|
||||
if (skb == NULL) {
|
||||
if (skb == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
arp_xmit(skb);
|
||||
}
|
||||
|
|
@ -815,7 +825,7 @@ static int arp_process(struct sk_buff *skb)
|
|||
/*
|
||||
* Extract fields
|
||||
*/
|
||||
arp_ptr= (unsigned char *)(arp+1);
|
||||
arp_ptr = (unsigned char *)(arp + 1);
|
||||
sha = arp_ptr;
|
||||
arp_ptr += dev->addr_len;
|
||||
memcpy(&sip, arp_ptr, 4);
|
||||
|
|
@ -869,16 +879,17 @@ static int arp_process(struct sk_buff *skb)
|
|||
addr_type = rt->rt_type;
|
||||
|
||||
if (addr_type == RTN_LOCAL) {
|
||||
int dont_send = 0;
|
||||
int dont_send;
|
||||
|
||||
if (!dont_send)
|
||||
dont_send |= arp_ignore(in_dev,sip,tip);
|
||||
dont_send = arp_ignore(in_dev, sip, tip);
|
||||
if (!dont_send && IN_DEV_ARPFILTER(in_dev))
|
||||
dont_send |= arp_filter(sip,tip,dev);
|
||||
dont_send |= arp_filter(sip, tip, dev);
|
||||
if (!dont_send) {
|
||||
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
|
||||
if (n) {
|
||||
arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
|
||||
arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
|
||||
dev, tip, sha, dev->dev_addr,
|
||||
sha);
|
||||
neigh_release(n);
|
||||
}
|
||||
}
|
||||
|
|
@ -887,8 +898,7 @@ static int arp_process(struct sk_buff *skb)
|
|||
if (addr_type == RTN_UNICAST &&
|
||||
(arp_fwd_proxy(in_dev, dev, rt) ||
|
||||
arp_fwd_pvlan(in_dev, dev, rt, sip, tip) ||
|
||||
pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))
|
||||
{
|
||||
pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) {
|
||||
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
|
||||
if (n)
|
||||
neigh_release(n);
|
||||
|
|
@ -896,9 +906,12 @@ static int arp_process(struct sk_buff *skb)
|
|||
if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
|
||||
skb->pkt_type == PACKET_HOST ||
|
||||
in_dev->arp_parms->proxy_delay == 0) {
|
||||
arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
|
||||
arp_send(ARPOP_REPLY, ETH_P_ARP, sip,
|
||||
dev, tip, sha, dev->dev_addr,
|
||||
sha);
|
||||
} else {
|
||||
pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
|
||||
pneigh_enqueue(&arp_tbl,
|
||||
in_dev->arp_parms, skb);
|
||||
return 0;
|
||||
}
|
||||
goto out;
|
||||
|
|
@ -939,7 +952,8 @@ static int arp_process(struct sk_buff *skb)
|
|||
if (arp->ar_op != htons(ARPOP_REPLY) ||
|
||||
skb->pkt_type != PACKET_HOST)
|
||||
state = NUD_STALE;
|
||||
neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);
|
||||
neigh_update(n, sha, state,
|
||||
override ? NEIGH_UPDATE_F_OVERRIDE : 0);
|
||||
neigh_release(n);
|
||||
}
|
||||
|
||||
|
|
@ -975,7 +989,8 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
|
|||
arp->ar_pln != 4)
|
||||
goto freeskb;
|
||||
|
||||
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
|
||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||
if (skb == NULL)
|
||||
goto out_of_mem;
|
||||
|
||||
memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
|
||||
|
|
@ -1019,7 +1034,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
|
|||
return -EINVAL;
|
||||
if (!dev && (r->arp_flags & ATF_COM)) {
|
||||
dev = dev_getbyhwaddr(net, r->arp_ha.sa_family,
|
||||
r->arp_ha.sa_data);
|
||||
r->arp_ha.sa_data);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -1033,7 +1048,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
|
|||
}
|
||||
|
||||
static int arp_req_set(struct net *net, struct arpreq *r,
|
||||
struct net_device * dev)
|
||||
struct net_device *dev)
|
||||
{
|
||||
__be32 ip;
|
||||
struct neighbour *neigh;
|
||||
|
|
@ -1046,10 +1061,11 @@ static int arp_req_set(struct net *net, struct arpreq *r,
|
|||
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_key(net, &rt, &fl)) != 0)
|
||||
struct flowi fl = { .nl_u.ip4_u = { .daddr = ip,
|
||||
.tos = RTO_ONLINK } };
|
||||
struct rtable *rt;
|
||||
err = ip_route_output_key(net, &rt, &fl);
|
||||
if (err != 0)
|
||||
return err;
|
||||
dev = rt->dst.dev;
|
||||
ip_rt_put(rt);
|
||||
|
|
@ -1083,9 +1099,9 @@ static int arp_req_set(struct net *net, struct arpreq *r,
|
|||
unsigned state = NUD_STALE;
|
||||
if (r->arp_flags & ATF_PERM)
|
||||
state = NUD_PERMANENT;
|
||||
err = neigh_update(neigh, (r->arp_flags&ATF_COM) ?
|
||||
err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
|
||||
r->arp_ha.sa_data : NULL, state,
|
||||
NEIGH_UPDATE_F_OVERRIDE|
|
||||
NEIGH_UPDATE_F_OVERRIDE |
|
||||
NEIGH_UPDATE_F_ADMIN);
|
||||
neigh_release(neigh);
|
||||
}
|
||||
|
|
@ -1094,12 +1110,12 @@ static int arp_req_set(struct net *net, struct arpreq *r,
|
|||
|
||||
static unsigned arp_state_to_flags(struct neighbour *neigh)
|
||||
{
|
||||
unsigned flags = 0;
|
||||
if (neigh->nud_state&NUD_PERMANENT)
|
||||
flags = ATF_PERM|ATF_COM;
|
||||
return ATF_PERM | ATF_COM;
|
||||
else if (neigh->nud_state&NUD_VALID)
|
||||
flags = ATF_COM;
|
||||
return flags;
|
||||
return ATF_COM;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1142,7 +1158,7 @@ static int arp_req_delete_public(struct net *net, struct arpreq *r,
|
|||
}
|
||||
|
||||
static int arp_req_delete(struct net *net, struct arpreq *r,
|
||||
struct net_device * dev)
|
||||
struct net_device *dev)
|
||||
{
|
||||
int err;
|
||||
__be32 ip;
|
||||
|
|
@ -1153,10 +1169,11 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
|
|||
|
||||
ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
|
||||
if (dev == NULL) {
|
||||
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
|
||||
.tos = RTO_ONLINK } } };
|
||||
struct rtable * rt;
|
||||
if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
|
||||
struct flowi fl = { .nl_u.ip4_u = { .daddr = ip,
|
||||
.tos = RTO_ONLINK } };
|
||||
struct rtable *rt;
|
||||
err = ip_route_output_key(net, &rt, &fl);
|
||||
if (err != 0)
|
||||
return err;
|
||||
dev = rt->dst.dev;
|
||||
ip_rt_put(rt);
|
||||
|
|
@ -1166,7 +1183,7 @@ static int arp_req_delete(struct net *net, struct arpreq *r,
|
|||
err = -ENXIO;
|
||||
neigh = neigh_lookup(&arp_tbl, &ip, dev);
|
||||
if (neigh) {
|
||||
if (neigh->nud_state&~NUD_NOARP)
|
||||
if (neigh->nud_state & ~NUD_NOARP)
|
||||
err = neigh_update(neigh, NULL, NUD_FAILED,
|
||||
NEIGH_UPDATE_F_OVERRIDE|
|
||||
NEIGH_UPDATE_F_ADMIN);
|
||||
|
|
@ -1186,24 +1203,24 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
|
|||
struct net_device *dev = NULL;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCDARP:
|
||||
case SIOCSARP:
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
case SIOCGARP:
|
||||
err = copy_from_user(&r, arg, sizeof(struct arpreq));
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
case SIOCDARP:
|
||||
case SIOCSARP:
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
case SIOCGARP:
|
||||
err = copy_from_user(&r, arg, sizeof(struct arpreq));
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (r.arp_pa.sa_family != AF_INET)
|
||||
return -EPFNOSUPPORT;
|
||||
|
||||
if (!(r.arp_flags & ATF_PUBL) &&
|
||||
(r.arp_flags & (ATF_NETMASK|ATF_DONTPUB)))
|
||||
(r.arp_flags & (ATF_NETMASK | ATF_DONTPUB)))
|
||||
return -EINVAL;
|
||||
if (!(r.arp_flags & ATF_NETMASK))
|
||||
((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
|
||||
|
|
@ -1211,7 +1228,8 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
|
|||
rtnl_lock();
|
||||
if (r.arp_dev[0]) {
|
||||
err = -ENODEV;
|
||||
if ((dev = __dev_get_by_name(net, r.arp_dev)) == NULL)
|
||||
dev = __dev_get_by_name(net, r.arp_dev);
|
||||
if (dev == NULL)
|
||||
goto out;
|
||||
|
||||
/* Mmmm... It is wrong... ARPHRD_NETROM==0 */
|
||||
|
|
@ -1243,7 +1261,8 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
|
||||
static int arp_netdev_event(struct notifier_block *this, unsigned long event,
|
||||
void *ptr)
|
||||
{
|
||||
struct net_device *dev = ptr;
|
||||
|
||||
|
|
@ -1311,12 +1330,13 @@ static char *ax2asc2(ax25_address *a, char *buf)
|
|||
for (n = 0, s = buf; n < 6; n++) {
|
||||
c = (a->ax25_call[n] >> 1) & 0x7F;
|
||||
|
||||
if (c != ' ') *s++ = c;
|
||||
if (c != ' ')
|
||||
*s++ = c;
|
||||
}
|
||||
|
||||
*s++ = '-';
|
||||
|
||||
if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
|
||||
n = (a->ax25_call[6] >> 1) & 0x0F;
|
||||
if (n > 9) {
|
||||
*s++ = '1';
|
||||
n -= 10;
|
||||
}
|
||||
|
|
@ -1325,10 +1345,9 @@ static char *ax2asc2(ax25_address *a, char *buf)
|
|||
*s++ = '\0';
|
||||
|
||||
if (*buf == '\0' || *buf == '-')
|
||||
return "*";
|
||||
return "*";
|
||||
|
||||
return buf;
|
||||
|
||||
}
|
||||
#endif /* CONFIG_AX25 */
|
||||
|
||||
|
|
@ -1408,10 +1427,10 @@ static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
|
|||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
static const struct seq_operations arp_seq_ops = {
|
||||
.start = arp_seq_start,
|
||||
.next = neigh_seq_next,
|
||||
.stop = neigh_seq_stop,
|
||||
.show = arp_seq_show,
|
||||
.start = arp_seq_start,
|
||||
.next = neigh_seq_next,
|
||||
.stop = neigh_seq_stop,
|
||||
.show = arp_seq_show,
|
||||
};
|
||||
|
||||
static int arp_seq_open(struct inode *inode, struct file *file)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,6 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
|||
inet->inet_id = jiffies;
|
||||
|
||||
sk_dst_set(sk, &rt->dst);
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ip4_datagram_connect);
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ static void inetdev_destroy(struct in_device *in_dev)
|
|||
inet_free_ifa(ifa);
|
||||
}
|
||||
|
||||
dev->ip_ptr = NULL;
|
||||
rcu_assign_pointer(dev->ip_ptr, NULL);
|
||||
|
||||
devinet_sysctl_unregister(in_dev);
|
||||
neigh_parms_release(&arp_tbl, in_dev->arp_parms);
|
||||
|
|
@ -403,6 +403,9 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
|
|||
return inet_insert_ifa(ifa);
|
||||
}
|
||||
|
||||
/* Caller must hold RCU or RTNL :
|
||||
* We dont take a reference on found in_device
|
||||
*/
|
||||
struct in_device *inetdev_by_index(struct net *net, int ifindex)
|
||||
{
|
||||
struct net_device *dev;
|
||||
|
|
@ -411,7 +414,7 @@ struct in_device *inetdev_by_index(struct net *net, int ifindex)
|
|||
rcu_read_lock();
|
||||
dev = dev_get_by_index_rcu(net, ifindex);
|
||||
if (dev)
|
||||
in_dev = in_dev_get(dev);
|
||||
in_dev = rcu_dereference_rtnl(dev->ip_ptr);
|
||||
rcu_read_unlock();
|
||||
return in_dev;
|
||||
}
|
||||
|
|
@ -453,8 +456,6 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
|
|||
goto errout;
|
||||
}
|
||||
|
||||
__in_dev_put(in_dev);
|
||||
|
||||
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
|
||||
ifap = &ifa->ifa_next) {
|
||||
if (tb[IFA_LOCAL] &&
|
||||
|
|
@ -1059,7 +1060,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
|
|||
switch (event) {
|
||||
case NETDEV_REGISTER:
|
||||
printk(KERN_DEBUG "inetdev_event: bug\n");
|
||||
dev->ip_ptr = NULL;
|
||||
rcu_assign_pointer(dev->ip_ptr, NULL);
|
||||
break;
|
||||
case NETDEV_UP:
|
||||
if (!inetdev_valid_mtu(dev->mtu))
|
||||
|
|
|
|||
|
|
@ -147,35 +147,43 @@ static void fib_flush(struct net *net)
|
|||
rt_cache_flush(net, -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the first device with a given source address.
|
||||
/**
|
||||
* __ip_dev_find - find the first device with a given source address.
|
||||
* @net: the net namespace
|
||||
* @addr: the source address
|
||||
* @devref: if true, take a reference on the found device
|
||||
*
|
||||
* If a caller uses devref=false, it should be protected by RCU, or RTNL
|
||||
*/
|
||||
|
||||
struct net_device * ip_dev_find(struct net *net, __be32 addr)
|
||||
struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
|
||||
{
|
||||
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
|
||||
struct fib_result res;
|
||||
struct flowi fl = {
|
||||
.nl_u = {
|
||||
.ip4_u = {
|
||||
.daddr = addr
|
||||
}
|
||||
},
|
||||
.flags = FLOWI_FLAG_MATCH_ANY_IIF
|
||||
};
|
||||
struct fib_result res = { 0 };
|
||||
struct net_device *dev = NULL;
|
||||
struct fib_table *local_table;
|
||||
|
||||
#ifdef CONFIG_IP_MULTIPLE_TABLES
|
||||
res.r = NULL;
|
||||
#endif
|
||||
|
||||
local_table = fib_get_table(net, RT_TABLE_LOCAL);
|
||||
if (!local_table || fib_table_lookup(local_table, &fl, &res))
|
||||
rcu_read_lock();
|
||||
if (fib_lookup(net, &fl, &res)) {
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
if (res.type != RTN_LOCAL)
|
||||
goto out;
|
||||
dev = FIB_RES_DEV(res);
|
||||
|
||||
if (dev)
|
||||
if (dev && devref)
|
||||
dev_hold(dev);
|
||||
out:
|
||||
fib_res_put(&res);
|
||||
rcu_read_unlock();
|
||||
return dev;
|
||||
}
|
||||
EXPORT_SYMBOL(ip_dev_find);
|
||||
EXPORT_SYMBOL(__ip_dev_find);
|
||||
|
||||
/*
|
||||
* Find address type as if only "dev" was present in the system. If
|
||||
|
|
@ -202,11 +210,12 @@ static inline unsigned __inet_dev_addr_type(struct net *net,
|
|||
local_table = fib_get_table(net, RT_TABLE_LOCAL);
|
||||
if (local_table) {
|
||||
ret = RTN_UNICAST;
|
||||
if (!fib_table_lookup(local_table, &fl, &res)) {
|
||||
rcu_read_lock();
|
||||
if (!fib_table_lookup(local_table, &fl, &res, FIB_LOOKUP_NOREF)) {
|
||||
if (!dev || dev == res.fi->fib_dev)
|
||||
ret = res.type;
|
||||
fib_res_put(&res);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -220,30 +229,34 @@ EXPORT_SYMBOL(inet_addr_type);
|
|||
unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
|
||||
__be32 addr)
|
||||
{
|
||||
return __inet_dev_addr_type(net, dev, addr);
|
||||
return __inet_dev_addr_type(net, dev, addr);
|
||||
}
|
||||
EXPORT_SYMBOL(inet_dev_addr_type);
|
||||
|
||||
/* Given (packet source, input interface) and optional (dst, oif, tos):
|
||||
- (main) check, that source is valid i.e. not broadcast or our local
|
||||
address.
|
||||
- figure out what "logical" interface this packet arrived
|
||||
and calculate "specific destination" address.
|
||||
- check, that packet arrived from expected physical interface.
|
||||
* - (main) check, that source is valid i.e. not broadcast or our local
|
||||
* address.
|
||||
* - figure out what "logical" interface this packet arrived
|
||||
* and calculate "specific destination" address.
|
||||
* - check, that packet arrived from expected physical interface.
|
||||
* called with rcu_read_lock()
|
||||
*/
|
||||
|
||||
int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
|
||||
struct net_device *dev, __be32 *spec_dst,
|
||||
u32 *itag, u32 mark)
|
||||
{
|
||||
struct in_device *in_dev;
|
||||
struct flowi fl = { .nl_u = { .ip4_u =
|
||||
{ .daddr = src,
|
||||
.saddr = dst,
|
||||
.tos = tos } },
|
||||
.mark = mark,
|
||||
.iif = oif };
|
||||
|
||||
struct flowi fl = {
|
||||
.nl_u = {
|
||||
.ip4_u = {
|
||||
.daddr = src,
|
||||
.saddr = dst,
|
||||
.tos = tos
|
||||
}
|
||||
},
|
||||
.mark = mark,
|
||||
.iif = oif
|
||||
};
|
||||
struct fib_result res;
|
||||
int no_addr, rpf, accept_local;
|
||||
bool dev_match;
|
||||
|
|
@ -251,7 +264,6 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
|
|||
struct net *net;
|
||||
|
||||
no_addr = rpf = accept_local = 0;
|
||||
rcu_read_lock();
|
||||
in_dev = __in_dev_get_rcu(dev);
|
||||
if (in_dev) {
|
||||
no_addr = in_dev->ifa_list == NULL;
|
||||
|
|
@ -260,7 +272,6 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
|
|||
if (mark && !IN_DEV_SRC_VMARK(in_dev))
|
||||
fl.mark = 0;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (in_dev == NULL)
|
||||
goto e_inval;
|
||||
|
|
@ -270,7 +281,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
|
|||
goto last_resort;
|
||||
if (res.type != RTN_UNICAST) {
|
||||
if (res.type != RTN_LOCAL || !accept_local)
|
||||
goto e_inval_res;
|
||||
goto e_inval;
|
||||
}
|
||||
*spec_dst = FIB_RES_PREFSRC(res);
|
||||
fib_combine_itag(itag, &res);
|
||||
|
|
@ -291,10 +302,8 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
|
|||
#endif
|
||||
if (dev_match) {
|
||||
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
|
||||
fib_res_put(&res);
|
||||
return ret;
|
||||
}
|
||||
fib_res_put(&res);
|
||||
if (no_addr)
|
||||
goto last_resort;
|
||||
if (rpf == 1)
|
||||
|
|
@ -307,7 +316,6 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
|
|||
*spec_dst = FIB_RES_PREFSRC(res);
|
||||
ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
|
||||
}
|
||||
fib_res_put(&res);
|
||||
}
|
||||
return ret;
|
||||
|
||||
|
|
@ -318,8 +326,6 @@ last_resort:
|
|||
*itag = 0;
|
||||
return 0;
|
||||
|
||||
e_inval_res:
|
||||
fib_res_put(&res);
|
||||
e_inval:
|
||||
return -EINVAL;
|
||||
e_rpf:
|
||||
|
|
@ -472,9 +478,9 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
|
|||
}
|
||||
|
||||
/*
|
||||
* Handle IP routing ioctl calls. These are used to manipulate the routing tables
|
||||
* Handle IP routing ioctl calls.
|
||||
* These are used to manipulate the routing tables
|
||||
*/
|
||||
|
||||
int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
|
||||
{
|
||||
struct fib_config cfg;
|
||||
|
|
@ -518,7 +524,7 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {
|
||||
const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
|
||||
[RTA_DST] = { .type = NLA_U32 },
|
||||
[RTA_SRC] = { .type = NLA_U32 },
|
||||
[RTA_IIF] = { .type = NLA_U32 },
|
||||
|
|
@ -532,7 +538,7 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {
|
|||
};
|
||||
|
||||
static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
|
||||
struct nlmsghdr *nlh, struct fib_config *cfg)
|
||||
struct nlmsghdr *nlh, struct fib_config *cfg)
|
||||
{
|
||||
struct nlattr *attr;
|
||||
int err, remaining;
|
||||
|
|
@ -687,12 +693,11 @@ out:
|
|||
}
|
||||
|
||||
/* Prepare and feed intra-kernel routing request.
|
||||
Really, it should be netlink message, but :-( netlink
|
||||
can be not configured, so that we feed it directly
|
||||
to fib engine. It is legal, because all events occur
|
||||
only when netlink is already locked.
|
||||
* Really, it should be netlink message, but :-( netlink
|
||||
* can be not configured, so that we feed it directly
|
||||
* to fib engine. It is legal, because all events occur
|
||||
* only when netlink is already locked.
|
||||
*/
|
||||
|
||||
static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
|
||||
{
|
||||
struct net *net = dev_net(ifa->ifa_dev->dev);
|
||||
|
|
@ -738,9 +743,9 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
|
|||
struct in_ifaddr *prim = ifa;
|
||||
__be32 mask = ifa->ifa_mask;
|
||||
__be32 addr = ifa->ifa_local;
|
||||
__be32 prefix = ifa->ifa_address&mask;
|
||||
__be32 prefix = ifa->ifa_address & mask;
|
||||
|
||||
if (ifa->ifa_flags&IFA_F_SECONDARY) {
|
||||
if (ifa->ifa_flags & IFA_F_SECONDARY) {
|
||||
prim = inet_ifa_byprefix(in_dev, prefix, mask);
|
||||
if (prim == NULL) {
|
||||
printk(KERN_WARNING "fib_add_ifaddr: bug: prim == NULL\n");
|
||||
|
|
@ -750,22 +755,24 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
|
|||
|
||||
fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
|
||||
|
||||
if (!(dev->flags&IFF_UP))
|
||||
if (!(dev->flags & IFF_UP))
|
||||
return;
|
||||
|
||||
/* Add broadcast address, if it is explicitly assigned. */
|
||||
if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
|
||||
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
|
||||
|
||||
if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
|
||||
if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
|
||||
(prefix != addr || ifa->ifa_prefixlen < 32)) {
|
||||
fib_magic(RTM_NEWROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
|
||||
RTN_UNICAST, prefix, ifa->ifa_prefixlen, prim);
|
||||
fib_magic(RTM_NEWROUTE,
|
||||
dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
|
||||
prefix, ifa->ifa_prefixlen, prim);
|
||||
|
||||
/* Add network specific broadcasts, when it takes a sense */
|
||||
if (ifa->ifa_prefixlen < 31) {
|
||||
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
|
||||
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix|~mask, 32, prim);
|
||||
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
|
||||
32, prim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -776,17 +783,18 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
|
|||
struct net_device *dev = in_dev->dev;
|
||||
struct in_ifaddr *ifa1;
|
||||
struct in_ifaddr *prim = ifa;
|
||||
__be32 brd = ifa->ifa_address|~ifa->ifa_mask;
|
||||
__be32 any = ifa->ifa_address&ifa->ifa_mask;
|
||||
__be32 brd = ifa->ifa_address | ~ifa->ifa_mask;
|
||||
__be32 any = ifa->ifa_address & ifa->ifa_mask;
|
||||
#define LOCAL_OK 1
|
||||
#define BRD_OK 2
|
||||
#define BRD0_OK 4
|
||||
#define BRD1_OK 8
|
||||
unsigned ok = 0;
|
||||
|
||||
if (!(ifa->ifa_flags&IFA_F_SECONDARY))
|
||||
fib_magic(RTM_DELROUTE, dev->flags&IFF_LOOPBACK ? RTN_LOCAL :
|
||||
RTN_UNICAST, any, ifa->ifa_prefixlen, prim);
|
||||
if (!(ifa->ifa_flags & IFA_F_SECONDARY))
|
||||
fib_magic(RTM_DELROUTE,
|
||||
dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
|
||||
any, ifa->ifa_prefixlen, prim);
|
||||
else {
|
||||
prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask);
|
||||
if (prim == NULL) {
|
||||
|
|
@ -796,9 +804,9 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
|
|||
}
|
||||
|
||||
/* Deletion is more complicated than add.
|
||||
We should take care of not to delete too much :-)
|
||||
|
||||
Scan address list to be sure that addresses are really gone.
|
||||
* We should take care of not to delete too much :-)
|
||||
*
|
||||
* Scan address list to be sure that addresses are really gone.
|
||||
*/
|
||||
|
||||
for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {
|
||||
|
|
@ -812,23 +820,23 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
|
|||
ok |= BRD0_OK;
|
||||
}
|
||||
|
||||
if (!(ok&BRD_OK))
|
||||
if (!(ok & BRD_OK))
|
||||
fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
|
||||
if (!(ok&BRD1_OK))
|
||||
if (!(ok & BRD1_OK))
|
||||
fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim);
|
||||
if (!(ok&BRD0_OK))
|
||||
if (!(ok & BRD0_OK))
|
||||
fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
|
||||
if (!(ok&LOCAL_OK)) {
|
||||
if (!(ok & LOCAL_OK)) {
|
||||
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
|
||||
|
||||
/* Check, that this local address finally disappeared. */
|
||||
if (inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
|
||||
/* And the last, but not the least thing.
|
||||
We must flush stray FIB entries.
|
||||
|
||||
First of all, we scan fib_info list searching
|
||||
for stray nexthop entries, then ignite fib_flush.
|
||||
*/
|
||||
* We must flush stray FIB entries.
|
||||
*
|
||||
* First of all, we scan fib_info list searching
|
||||
* for stray nexthop entries, then ignite fib_flush.
|
||||
*/
|
||||
if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local))
|
||||
fib_flush(dev_net(dev));
|
||||
}
|
||||
|
|
@ -839,14 +847,20 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
|
|||
#undef BRD1_OK
|
||||
}
|
||||
|
||||
static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
|
||||
static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
|
||||
{
|
||||
|
||||
struct fib_result res;
|
||||
struct flowi fl = { .mark = frn->fl_mark,
|
||||
.nl_u = { .ip4_u = { .daddr = frn->fl_addr,
|
||||
.tos = frn->fl_tos,
|
||||
.scope = frn->fl_scope } } };
|
||||
struct flowi fl = {
|
||||
.mark = frn->fl_mark,
|
||||
.nl_u = {
|
||||
.ip4_u = {
|
||||
.daddr = frn->fl_addr,
|
||||
.tos = frn->fl_tos,
|
||||
.scope = frn->fl_scope
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IP_MULTIPLE_TABLES
|
||||
res.r = NULL;
|
||||
|
|
@ -857,15 +871,16 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
|
|||
local_bh_disable();
|
||||
|
||||
frn->tb_id = tb->tb_id;
|
||||
frn->err = fib_table_lookup(tb, &fl, &res);
|
||||
rcu_read_lock();
|
||||
frn->err = fib_table_lookup(tb, &fl, &res, FIB_LOOKUP_NOREF);
|
||||
|
||||
if (!frn->err) {
|
||||
frn->prefixlen = res.prefixlen;
|
||||
frn->nh_sel = res.nh_sel;
|
||||
frn->type = res.type;
|
||||
frn->scope = res.scope;
|
||||
fib_res_put(&res);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
local_bh_enable();
|
||||
}
|
||||
}
|
||||
|
|
@ -894,8 +909,8 @@ static void nl_fib_input(struct sk_buff *skb)
|
|||
|
||||
nl_fib_lookup(frn, tb);
|
||||
|
||||
pid = NETLINK_CB(skb).pid; /* pid of sending process */
|
||||
NETLINK_CB(skb).pid = 0; /* from kernel */
|
||||
pid = NETLINK_CB(skb).pid; /* pid of sending process */
|
||||
NETLINK_CB(skb).pid = 0; /* from kernel */
|
||||
NETLINK_CB(skb).dst_group = 0; /* unicast */
|
||||
netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT);
|
||||
}
|
||||
|
|
@ -942,7 +957,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
|
|||
fib_del_ifaddr(ifa);
|
||||
if (ifa->ifa_dev->ifa_list == NULL) {
|
||||
/* Last address was deleted from this interface.
|
||||
Disable IP.
|
||||
* Disable IP.
|
||||
*/
|
||||
fib_disable_ip(dev, 1, 0);
|
||||
} else {
|
||||
|
|
@ -1001,16 +1016,15 @@ static struct notifier_block fib_netdev_notifier = {
|
|||
static int __net_init ip_fib_net_init(struct net *net)
|
||||
{
|
||||
int err;
|
||||
unsigned int i;
|
||||
size_t size = sizeof(struct hlist_head) * FIB_TABLE_HASHSZ;
|
||||
|
||||
net->ipv4.fib_table_hash = kzalloc(
|
||||
sizeof(struct hlist_head)*FIB_TABLE_HASHSZ, GFP_KERNEL);
|
||||
/* Avoid false sharing : Use at least a full cache line */
|
||||
size = max_t(size_t, size, L1_CACHE_BYTES);
|
||||
|
||||
net->ipv4.fib_table_hash = kzalloc(size, GFP_KERNEL);
|
||||
if (net->ipv4.fib_table_hash == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < FIB_TABLE_HASHSZ; i++)
|
||||
INIT_HLIST_HEAD(&net->ipv4.fib_table_hash[i]);
|
||||
|
||||
err = fib4_rules_init(net);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -54,36 +54,37 @@ struct fib_node {
|
|||
struct fib_alias fn_embedded_alias;
|
||||
};
|
||||
|
||||
#define EMBEDDED_HASH_SIZE (L1_CACHE_BYTES / sizeof(struct hlist_head))
|
||||
|
||||
struct fn_zone {
|
||||
struct fn_zone *fz_next; /* Next not empty zone */
|
||||
struct hlist_head *fz_hash; /* Hash table pointer */
|
||||
int fz_nent; /* Number of entries */
|
||||
|
||||
int fz_divisor; /* Hash divisor */
|
||||
struct fn_zone __rcu *fz_next; /* Next not empty zone */
|
||||
struct hlist_head __rcu *fz_hash; /* Hash table pointer */
|
||||
seqlock_t fz_lock;
|
||||
u32 fz_hashmask; /* (fz_divisor - 1) */
|
||||
#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
|
||||
|
||||
int fz_order; /* Zone order */
|
||||
__be32 fz_mask;
|
||||
u8 fz_order; /* Zone order (0..32) */
|
||||
u8 fz_revorder; /* 32 - fz_order */
|
||||
__be32 fz_mask; /* inet_make_mask(order) */
|
||||
#define FZ_MASK(fz) ((fz)->fz_mask)
|
||||
|
||||
struct hlist_head fz_embedded_hash[EMBEDDED_HASH_SIZE];
|
||||
|
||||
int fz_nent; /* Number of entries */
|
||||
int fz_divisor; /* Hash size (mask+1) */
|
||||
};
|
||||
|
||||
/* NOTE. On fast computers evaluation of fz_hashmask and fz_mask
|
||||
* can be cheaper than memory lookup, so that FZ_* macros are used.
|
||||
*/
|
||||
|
||||
struct fn_hash {
|
||||
struct fn_zone *fn_zones[33];
|
||||
struct fn_zone *fn_zone_list;
|
||||
struct fn_zone *fn_zones[33];
|
||||
struct fn_zone __rcu *fn_zone_list;
|
||||
};
|
||||
|
||||
static inline u32 fn_hash(__be32 key, struct fn_zone *fz)
|
||||
{
|
||||
u32 h = ntohl(key)>>(32 - fz->fz_order);
|
||||
u32 h = ntohl(key) >> fz->fz_revorder;
|
||||
h ^= (h>>20);
|
||||
h ^= (h>>10);
|
||||
h ^= (h>>5);
|
||||
h &= FZ_HASHMASK(fz);
|
||||
h &= fz->fz_hashmask;
|
||||
return h;
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +93,6 @@ static inline __be32 fz_key(__be32 dst, struct fn_zone *fz)
|
|||
return dst & FZ_MASK(fz);
|
||||
}
|
||||
|
||||
static DEFINE_RWLOCK(fib_hash_lock);
|
||||
static unsigned int fib_hash_genid;
|
||||
|
||||
#define FZ_MAX_DIVISOR ((PAGE_SIZE<<MAX_ORDER) / sizeof(struct hlist_head))
|
||||
|
|
@ -101,12 +101,11 @@ static struct hlist_head *fz_hash_alloc(int divisor)
|
|||
{
|
||||
unsigned long size = divisor * sizeof(struct hlist_head);
|
||||
|
||||
if (size <= PAGE_SIZE) {
|
||||
if (size <= PAGE_SIZE)
|
||||
return kzalloc(size, GFP_KERNEL);
|
||||
} else {
|
||||
return (struct hlist_head *)
|
||||
__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(size));
|
||||
}
|
||||
|
||||
return (struct hlist_head *)
|
||||
__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(size));
|
||||
}
|
||||
|
||||
/* The fib hash lock must be held when this is called. */
|
||||
|
|
@ -121,12 +120,12 @@ static inline void fn_rebuild_zone(struct fn_zone *fz,
|
|||
struct fib_node *f;
|
||||
|
||||
hlist_for_each_entry_safe(f, node, n, &old_ht[i], fn_hash) {
|
||||
struct hlist_head *new_head;
|
||||
struct hlist_head __rcu *new_head;
|
||||
|
||||
hlist_del(&f->fn_hash);
|
||||
hlist_del_rcu(&f->fn_hash);
|
||||
|
||||
new_head = &fz->fz_hash[fn_hash(f->fn_key, fz)];
|
||||
hlist_add_head(&f->fn_hash, new_head);
|
||||
hlist_add_head_rcu(&f->fn_hash, new_head);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -147,14 +146,14 @@ static void fn_rehash_zone(struct fn_zone *fz)
|
|||
int old_divisor, new_divisor;
|
||||
u32 new_hashmask;
|
||||
|
||||
old_divisor = fz->fz_divisor;
|
||||
new_divisor = old_divisor = fz->fz_divisor;
|
||||
|
||||
switch (old_divisor) {
|
||||
case 16:
|
||||
new_divisor = 256;
|
||||
case EMBEDDED_HASH_SIZE:
|
||||
new_divisor *= EMBEDDED_HASH_SIZE;
|
||||
break;
|
||||
case 256:
|
||||
new_divisor = 1024;
|
||||
case EMBEDDED_HASH_SIZE*EMBEDDED_HASH_SIZE:
|
||||
new_divisor *= (EMBEDDED_HASH_SIZE/2);
|
||||
break;
|
||||
default:
|
||||
if ((old_divisor << 1) > FZ_MAX_DIVISOR) {
|
||||
|
|
@ -175,31 +174,55 @@ static void fn_rehash_zone(struct fn_zone *fz)
|
|||
ht = fz_hash_alloc(new_divisor);
|
||||
|
||||
if (ht) {
|
||||
write_lock_bh(&fib_hash_lock);
|
||||
struct fn_zone nfz;
|
||||
|
||||
memcpy(&nfz, fz, sizeof(nfz));
|
||||
|
||||
write_seqlock_bh(&fz->fz_lock);
|
||||
old_ht = fz->fz_hash;
|
||||
fz->fz_hash = ht;
|
||||
nfz.fz_hash = ht;
|
||||
nfz.fz_hashmask = new_hashmask;
|
||||
nfz.fz_divisor = new_divisor;
|
||||
fn_rebuild_zone(&nfz, old_ht, old_divisor);
|
||||
fib_hash_genid++;
|
||||
rcu_assign_pointer(fz->fz_hash, ht);
|
||||
fz->fz_hashmask = new_hashmask;
|
||||
fz->fz_divisor = new_divisor;
|
||||
fn_rebuild_zone(fz, old_ht, old_divisor);
|
||||
fib_hash_genid++;
|
||||
write_unlock_bh(&fib_hash_lock);
|
||||
write_sequnlock_bh(&fz->fz_lock);
|
||||
|
||||
fz_hash_free(old_ht, old_divisor);
|
||||
if (old_ht != fz->fz_embedded_hash) {
|
||||
synchronize_rcu();
|
||||
fz_hash_free(old_ht, old_divisor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void fn_free_node(struct fib_node * f)
|
||||
static void fn_free_node_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct fib_node *f = container_of(head, struct fib_node, fn_embedded_alias.rcu);
|
||||
|
||||
kmem_cache_free(fn_hash_kmem, f);
|
||||
}
|
||||
|
||||
static inline void fn_free_node(struct fib_node *f)
|
||||
{
|
||||
call_rcu(&f->fn_embedded_alias.rcu, fn_free_node_rcu);
|
||||
}
|
||||
|
||||
static void fn_free_alias_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct fib_alias *fa = container_of(head, struct fib_alias, rcu);
|
||||
|
||||
kmem_cache_free(fn_alias_kmem, fa);
|
||||
}
|
||||
|
||||
static inline void fn_free_alias(struct fib_alias *fa, struct fib_node *f)
|
||||
{
|
||||
fib_release_info(fa->fa_info);
|
||||
if (fa == &f->fn_embedded_alias)
|
||||
fa->fa_info = NULL;
|
||||
else
|
||||
kmem_cache_free(fn_alias_kmem, fa);
|
||||
call_rcu(&fa->rcu, fn_free_alias_rcu);
|
||||
}
|
||||
|
||||
static struct fn_zone *
|
||||
|
|
@ -210,68 +233,71 @@ fn_new_zone(struct fn_hash *table, int z)
|
|||
if (!fz)
|
||||
return NULL;
|
||||
|
||||
if (z) {
|
||||
fz->fz_divisor = 16;
|
||||
} else {
|
||||
fz->fz_divisor = 1;
|
||||
}
|
||||
fz->fz_hashmask = (fz->fz_divisor - 1);
|
||||
fz->fz_hash = fz_hash_alloc(fz->fz_divisor);
|
||||
if (!fz->fz_hash) {
|
||||
kfree(fz);
|
||||
return NULL;
|
||||
}
|
||||
seqlock_init(&fz->fz_lock);
|
||||
fz->fz_divisor = z ? EMBEDDED_HASH_SIZE : 1;
|
||||
fz->fz_hashmask = fz->fz_divisor - 1;
|
||||
fz->fz_hash = fz->fz_embedded_hash;
|
||||
fz->fz_order = z;
|
||||
fz->fz_revorder = 32 - z;
|
||||
fz->fz_mask = inet_make_mask(z);
|
||||
|
||||
/* Find the first not empty zone with more specific mask */
|
||||
for (i=z+1; i<=32; i++)
|
||||
for (i = z + 1; i <= 32; i++)
|
||||
if (table->fn_zones[i])
|
||||
break;
|
||||
write_lock_bh(&fib_hash_lock);
|
||||
if (i>32) {
|
||||
if (i > 32) {
|
||||
/* No more specific masks, we are the first. */
|
||||
fz->fz_next = table->fn_zone_list;
|
||||
table->fn_zone_list = fz;
|
||||
rcu_assign_pointer(fz->fz_next,
|
||||
rtnl_dereference(table->fn_zone_list));
|
||||
rcu_assign_pointer(table->fn_zone_list, fz);
|
||||
} else {
|
||||
fz->fz_next = table->fn_zones[i]->fz_next;
|
||||
table->fn_zones[i]->fz_next = fz;
|
||||
rcu_assign_pointer(fz->fz_next,
|
||||
rtnl_dereference(table->fn_zones[i]->fz_next));
|
||||
rcu_assign_pointer(table->fn_zones[i]->fz_next, fz);
|
||||
}
|
||||
table->fn_zones[z] = fz;
|
||||
fib_hash_genid++;
|
||||
write_unlock_bh(&fib_hash_lock);
|
||||
return fz;
|
||||
}
|
||||
|
||||
int fib_table_lookup(struct fib_table *tb,
|
||||
const struct flowi *flp, struct fib_result *res)
|
||||
const struct flowi *flp, struct fib_result *res,
|
||||
int fib_flags)
|
||||
{
|
||||
int err;
|
||||
struct fn_zone *fz;
|
||||
struct fn_hash *t = (struct fn_hash *)tb->tb_data;
|
||||
|
||||
read_lock(&fib_hash_lock);
|
||||
for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
|
||||
struct hlist_head *head;
|
||||
rcu_read_lock();
|
||||
for (fz = rcu_dereference(t->fn_zone_list);
|
||||
fz != NULL;
|
||||
fz = rcu_dereference(fz->fz_next)) {
|
||||
struct hlist_head __rcu *head;
|
||||
struct hlist_node *node;
|
||||
struct fib_node *f;
|
||||
__be32 k = fz_key(flp->fl4_dst, fz);
|
||||
__be32 k;
|
||||
unsigned int seq;
|
||||
|
||||
head = &fz->fz_hash[fn_hash(k, fz)];
|
||||
hlist_for_each_entry(f, node, head, fn_hash) {
|
||||
if (f->fn_key != k)
|
||||
continue;
|
||||
do {
|
||||
seq = read_seqbegin(&fz->fz_lock);
|
||||
k = fz_key(flp->fl4_dst, fz);
|
||||
|
||||
err = fib_semantic_match(&f->fn_alias,
|
||||
head = &fz->fz_hash[fn_hash(k, fz)];
|
||||
hlist_for_each_entry_rcu(f, node, head, fn_hash) {
|
||||
if (f->fn_key != k)
|
||||
continue;
|
||||
|
||||
err = fib_semantic_match(&f->fn_alias,
|
||||
flp, res,
|
||||
fz->fz_order);
|
||||
if (err <= 0)
|
||||
goto out;
|
||||
}
|
||||
fz->fz_order, fib_flags);
|
||||
if (err <= 0)
|
||||
goto out;
|
||||
}
|
||||
} while (read_seqretry(&fz->fz_lock, seq));
|
||||
}
|
||||
err = 1;
|
||||
out:
|
||||
read_unlock(&fib_hash_lock);
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -293,11 +319,11 @@ void fib_table_select_default(struct fib_table *tb,
|
|||
last_resort = NULL;
|
||||
order = -1;
|
||||
|
||||
read_lock(&fib_hash_lock);
|
||||
hlist_for_each_entry(f, node, &fz->fz_hash[0], fn_hash) {
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(f, node, &fz->fz_hash[0], fn_hash) {
|
||||
struct fib_alias *fa;
|
||||
|
||||
list_for_each_entry(fa, &f->fn_alias, fa_list) {
|
||||
list_for_each_entry_rcu(fa, &f->fn_alias, fa_list) {
|
||||
struct fib_info *next_fi = fa->fa_info;
|
||||
|
||||
if (fa->fa_scope != res->scope ||
|
||||
|
|
@ -309,7 +335,8 @@ void fib_table_select_default(struct fib_table *tb,
|
|||
if (!next_fi->fib_nh[0].nh_gw ||
|
||||
next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
|
||||
continue;
|
||||
fa->fa_state |= FA_S_ACCESSED;
|
||||
|
||||
fib_alias_accessed(fa);
|
||||
|
||||
if (fi == NULL) {
|
||||
if (next_fi != res->fi)
|
||||
|
|
@ -341,7 +368,7 @@ void fib_table_select_default(struct fib_table *tb,
|
|||
fib_result_assign(res, last_resort);
|
||||
tb->tb_default = last_idx;
|
||||
out:
|
||||
read_unlock(&fib_hash_lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* Insert node F to FZ. */
|
||||
|
|
@ -349,7 +376,7 @@ static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f)
|
|||
{
|
||||
struct hlist_head *head = &fz->fz_hash[fn_hash(f->fn_key, fz)];
|
||||
|
||||
hlist_add_head(&f->fn_hash, head);
|
||||
hlist_add_head_rcu(&f->fn_hash, head);
|
||||
}
|
||||
|
||||
/* Return the node in FZ matching KEY. */
|
||||
|
|
@ -359,7 +386,7 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
|
|||
struct hlist_node *node;
|
||||
struct fib_node *f;
|
||||
|
||||
hlist_for_each_entry(f, node, head, fn_hash) {
|
||||
hlist_for_each_entry_rcu(f, node, head, fn_hash) {
|
||||
if (f->fn_key == key)
|
||||
return f;
|
||||
}
|
||||
|
|
@ -367,6 +394,17 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct fib_alias *fib_fast_alloc(struct fib_node *f)
|
||||
{
|
||||
struct fib_alias *fa = &f->fn_embedded_alias;
|
||||
|
||||
if (fa->fa_info != NULL)
|
||||
fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
|
||||
return fa;
|
||||
}
|
||||
|
||||
/* Caller must hold RTNL. */
|
||||
int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
|
||||
{
|
||||
struct fn_hash *table = (struct fn_hash *) tb->tb_data;
|
||||
|
|
@ -451,7 +489,6 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
|
|||
}
|
||||
|
||||
if (cfg->fc_nlflags & NLM_F_REPLACE) {
|
||||
struct fib_info *fi_drop;
|
||||
u8 state;
|
||||
|
||||
fa = fa_first;
|
||||
|
|
@ -460,21 +497,25 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
|
|||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
write_lock_bh(&fib_hash_lock);
|
||||
fi_drop = fa->fa_info;
|
||||
fa->fa_info = fi;
|
||||
fa->fa_type = cfg->fc_type;
|
||||
fa->fa_scope = cfg->fc_scope;
|
||||
state = fa->fa_state;
|
||||
fa->fa_state &= ~FA_S_ACCESSED;
|
||||
fib_hash_genid++;
|
||||
write_unlock_bh(&fib_hash_lock);
|
||||
err = -ENOBUFS;
|
||||
new_fa = fib_fast_alloc(f);
|
||||
if (new_fa == NULL)
|
||||
goto out;
|
||||
|
||||
fib_release_info(fi_drop);
|
||||
new_fa->fa_tos = fa->fa_tos;
|
||||
new_fa->fa_info = fi;
|
||||
new_fa->fa_type = cfg->fc_type;
|
||||
new_fa->fa_scope = cfg->fc_scope;
|
||||
state = fa->fa_state;
|
||||
new_fa->fa_state = state & ~FA_S_ACCESSED;
|
||||
fib_hash_genid++;
|
||||
list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
|
||||
|
||||
fn_free_alias(fa, f);
|
||||
if (state & FA_S_ACCESSED)
|
||||
rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
|
||||
rtmsg_fib(RTM_NEWROUTE, key, fa, cfg->fc_dst_len, tb->tb_id,
|
||||
&cfg->fc_nlinfo, NLM_F_REPLACE);
|
||||
rtmsg_fib(RTM_NEWROUTE, key, new_fa, cfg->fc_dst_len,
|
||||
tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -506,12 +547,10 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
|
|||
f = new_f;
|
||||
}
|
||||
|
||||
new_fa = &f->fn_embedded_alias;
|
||||
if (new_fa->fa_info != NULL) {
|
||||
new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
|
||||
if (new_fa == NULL)
|
||||
goto out;
|
||||
}
|
||||
new_fa = fib_fast_alloc(f);
|
||||
if (new_fa == NULL)
|
||||
goto out;
|
||||
|
||||
new_fa->fa_info = fi;
|
||||
new_fa->fa_tos = tos;
|
||||
new_fa->fa_type = cfg->fc_type;
|
||||
|
|
@ -522,13 +561,11 @@ int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
|
|||
* Insert new entry to the list.
|
||||
*/
|
||||
|
||||
write_lock_bh(&fib_hash_lock);
|
||||
if (new_f)
|
||||
fib_insert_node(fz, new_f);
|
||||
list_add_tail(&new_fa->fa_list,
|
||||
list_add_tail_rcu(&new_fa->fa_list,
|
||||
(fa ? &fa->fa_list : &f->fn_alias));
|
||||
fib_hash_genid++;
|
||||
write_unlock_bh(&fib_hash_lock);
|
||||
|
||||
if (new_f)
|
||||
fz->fz_nent++;
|
||||
|
|
@ -603,14 +640,12 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
|
|||
tb->tb_id, &cfg->fc_nlinfo, 0);
|
||||
|
||||
kill_fn = 0;
|
||||
write_lock_bh(&fib_hash_lock);
|
||||
list_del(&fa->fa_list);
|
||||
list_del_rcu(&fa->fa_list);
|
||||
if (list_empty(&f->fn_alias)) {
|
||||
hlist_del(&f->fn_hash);
|
||||
hlist_del_rcu(&f->fn_hash);
|
||||
kill_fn = 1;
|
||||
}
|
||||
fib_hash_genid++;
|
||||
write_unlock_bh(&fib_hash_lock);
|
||||
|
||||
if (fa->fa_state & FA_S_ACCESSED)
|
||||
rt_cache_flush(cfg->fc_nlinfo.nl_net, -1);
|
||||
|
|
@ -641,14 +676,12 @@ static int fn_flush_list(struct fn_zone *fz, int idx)
|
|||
struct fib_info *fi = fa->fa_info;
|
||||
|
||||
if (fi && (fi->fib_flags&RTNH_F_DEAD)) {
|
||||
write_lock_bh(&fib_hash_lock);
|
||||
list_del(&fa->fa_list);
|
||||
list_del_rcu(&fa->fa_list);
|
||||
if (list_empty(&f->fn_alias)) {
|
||||
hlist_del(&f->fn_hash);
|
||||
hlist_del_rcu(&f->fn_hash);
|
||||
kill_f = 1;
|
||||
}
|
||||
fib_hash_genid++;
|
||||
write_unlock_bh(&fib_hash_lock);
|
||||
|
||||
fn_free_alias(fa, f);
|
||||
found++;
|
||||
|
|
@ -662,13 +695,16 @@ static int fn_flush_list(struct fn_zone *fz, int idx)
|
|||
return found;
|
||||
}
|
||||
|
||||
/* caller must hold RTNL. */
|
||||
int fib_table_flush(struct fib_table *tb)
|
||||
{
|
||||
struct fn_hash *table = (struct fn_hash *) tb->tb_data;
|
||||
struct fn_zone *fz;
|
||||
int found = 0;
|
||||
|
||||
for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
|
||||
for (fz = rtnl_dereference(table->fn_zone_list);
|
||||
fz != NULL;
|
||||
fz = rtnl_dereference(fz->fz_next)) {
|
||||
int i;
|
||||
|
||||
for (i = fz->fz_divisor - 1; i >= 0; i--)
|
||||
|
|
@ -690,10 +726,10 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
|
|||
|
||||
s_i = cb->args[4];
|
||||
i = 0;
|
||||
hlist_for_each_entry(f, node, head, fn_hash) {
|
||||
hlist_for_each_entry_rcu(f, node, head, fn_hash) {
|
||||
struct fib_alias *fa;
|
||||
|
||||
list_for_each_entry(fa, &f->fn_alias, fa_list) {
|
||||
list_for_each_entry_rcu(fa, &f->fn_alias, fa_list) {
|
||||
if (i < s_i)
|
||||
goto next;
|
||||
|
||||
|
|
@ -711,7 +747,7 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
|
|||
cb->args[4] = i;
|
||||
return -1;
|
||||
}
|
||||
next:
|
||||
next:
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
|
@ -746,23 +782,26 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
|
|||
int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
int m, s_m;
|
||||
int m = 0, s_m;
|
||||
struct fn_zone *fz;
|
||||
struct fn_hash *table = (struct fn_hash *)tb->tb_data;
|
||||
|
||||
s_m = cb->args[2];
|
||||
read_lock(&fib_hash_lock);
|
||||
for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
|
||||
if (m < s_m) continue;
|
||||
rcu_read_lock();
|
||||
for (fz = rcu_dereference(table->fn_zone_list);
|
||||
fz != NULL;
|
||||
fz = rcu_dereference(fz->fz_next), m++) {
|
||||
if (m < s_m)
|
||||
continue;
|
||||
if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
|
||||
cb->args[2] = m;
|
||||
read_unlock(&fib_hash_lock);
|
||||
rcu_read_unlock();
|
||||
return -1;
|
||||
}
|
||||
memset(&cb->args[3], 0,
|
||||
sizeof(cb->args) - 3*sizeof(cb->args[0]));
|
||||
}
|
||||
read_unlock(&fib_hash_lock);
|
||||
rcu_read_unlock();
|
||||
cb->args[2] = m;
|
||||
return skb->len;
|
||||
}
|
||||
|
|
@ -825,8 +864,9 @@ static struct fib_alias *fib_get_first(struct seq_file *seq)
|
|||
iter->genid = fib_hash_genid;
|
||||
iter->valid = 1;
|
||||
|
||||
for (iter->zone = table->fn_zone_list; iter->zone;
|
||||
iter->zone = iter->zone->fz_next) {
|
||||
for (iter->zone = rcu_dereference(table->fn_zone_list);
|
||||
iter->zone != NULL;
|
||||
iter->zone = rcu_dereference(iter->zone->fz_next)) {
|
||||
int maxslot;
|
||||
|
||||
if (!iter->zone->fz_nent)
|
||||
|
|
@ -911,7 +951,7 @@ static struct fib_alias *fib_get_next(struct seq_file *seq)
|
|||
}
|
||||
}
|
||||
|
||||
iter->zone = iter->zone->fz_next;
|
||||
iter->zone = rcu_dereference(iter->zone->fz_next);
|
||||
|
||||
if (!iter->zone)
|
||||
goto out;
|
||||
|
|
@ -950,11 +990,11 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos)
|
|||
}
|
||||
|
||||
static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
__acquires(fib_hash_lock)
|
||||
__acquires(RCU)
|
||||
{
|
||||
void *v = NULL;
|
||||
|
||||
read_lock(&fib_hash_lock);
|
||||
rcu_read_lock();
|
||||
if (fib_get_table(seq_file_net(seq), RT_TABLE_MAIN))
|
||||
v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
|
||||
return v;
|
||||
|
|
@ -967,15 +1007,16 @@ static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|||
}
|
||||
|
||||
static void fib_seq_stop(struct seq_file *seq, void *v)
|
||||
__releases(fib_hash_lock)
|
||||
__releases(RCU)
|
||||
{
|
||||
read_unlock(&fib_hash_lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
|
||||
{
|
||||
static const unsigned type2flags[RTN_MAX + 1] = {
|
||||
[7] = RTF_REJECT, [8] = RTF_REJECT,
|
||||
[7] = RTF_REJECT,
|
||||
[8] = RTF_REJECT,
|
||||
};
|
||||
unsigned flags = type2flags[type];
|
||||
|
||||
|
|
|
|||
|
|
@ -12,17 +12,22 @@ struct fib_alias {
|
|||
u8 fa_type;
|
||||
u8 fa_scope;
|
||||
u8 fa_state;
|
||||
#ifdef CONFIG_IP_FIB_TRIE
|
||||
struct rcu_head rcu;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define FA_S_ACCESSED 0x01
|
||||
|
||||
/* Dont write on fa_state unless needed, to keep it shared on all cpus */
|
||||
static inline void fib_alias_accessed(struct fib_alias *fa)
|
||||
{
|
||||
if (!(fa->fa_state & FA_S_ACCESSED))
|
||||
fa->fa_state |= FA_S_ACCESSED;
|
||||
}
|
||||
|
||||
/* Exported by fib_semantics.c */
|
||||
extern int fib_semantic_match(struct list_head *head,
|
||||
const struct flowi *flp,
|
||||
struct fib_result *res, int prefixlen);
|
||||
struct fib_result *res, int prefixlen, int fib_flags);
|
||||
extern void fib_release_info(struct fib_info *);
|
||||
extern struct fib_info *fib_create_info(struct fib_config *cfg);
|
||||
extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* IPv4 Forwarding Information Base: policy rules.
|
||||
*
|
||||
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
|
||||
* Thomas Graf <tgraf@suug.ch>
|
||||
* Thomas Graf <tgraf@suug.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Fixes:
|
||||
* Rani Assaf : local_rule cannot be deleted
|
||||
* Rani Assaf : local_rule cannot be deleted
|
||||
* Marc Boucher : routing by fwmark
|
||||
*/
|
||||
|
||||
|
|
@ -32,8 +32,7 @@
|
|||
#include <net/ip_fib.h>
|
||||
#include <net/fib_rules.h>
|
||||
|
||||
struct fib4_rule
|
||||
{
|
||||
struct fib4_rule {
|
||||
struct fib_rule common;
|
||||
u8 dst_len;
|
||||
u8 src_len;
|
||||
|
|
@ -58,6 +57,7 @@ int fib_lookup(struct net *net, struct flowi *flp, struct fib_result *res)
|
|||
{
|
||||
struct fib_lookup_arg arg = {
|
||||
.result = res,
|
||||
.flags = FIB_LOOKUP_NOREF,
|
||||
};
|
||||
int err;
|
||||
|
||||
|
|
@ -91,10 +91,11 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
|
|||
goto errout;
|
||||
}
|
||||
|
||||
if ((tbl = fib_get_table(rule->fr_net, rule->table)) == NULL)
|
||||
tbl = fib_get_table(rule->fr_net, rule->table);
|
||||
if (!tbl)
|
||||
goto errout;
|
||||
|
||||
err = fib_table_lookup(tbl, flp, (struct fib_result *) arg->result);
|
||||
err = fib_table_lookup(tbl, flp, (struct fib_result *) arg->result, arg->flags);
|
||||
if (err > 0)
|
||||
err = -EAGAIN;
|
||||
errout:
|
||||
|
|
|
|||
|
|
@ -60,21 +60,30 @@ static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE];
|
|||
|
||||
static DEFINE_SPINLOCK(fib_multipath_lock);
|
||||
|
||||
#define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
|
||||
for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
|
||||
#define for_nexthops(fi) { \
|
||||
int nhsel; const struct fib_nh *nh; \
|
||||
for (nhsel = 0, nh = (fi)->fib_nh; \
|
||||
nhsel < (fi)->fib_nhs; \
|
||||
nh++, nhsel++)
|
||||
|
||||
#define change_nexthops(fi) { int nhsel; struct fib_nh *nexthop_nh; \
|
||||
for (nhsel=0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nexthop_nh++, nhsel++)
|
||||
#define change_nexthops(fi) { \
|
||||
int nhsel; struct fib_nh *nexthop_nh; \
|
||||
for (nhsel = 0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
|
||||
nhsel < (fi)->fib_nhs; \
|
||||
nexthop_nh++, nhsel++)
|
||||
|
||||
#else /* CONFIG_IP_ROUTE_MULTIPATH */
|
||||
|
||||
/* Hope, that gcc will optimize it to get rid of dummy loop */
|
||||
|
||||
#define for_nexthops(fi) { int nhsel = 0; const struct fib_nh * nh = (fi)->fib_nh; \
|
||||
for (nhsel=0; nhsel < 1; nhsel++)
|
||||
#define for_nexthops(fi) { \
|
||||
int nhsel; const struct fib_nh *nh = (fi)->fib_nh; \
|
||||
for (nhsel = 0; nhsel < 1; nhsel++)
|
||||
|
||||
#define change_nexthops(fi) { int nhsel = 0; struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
|
||||
for (nhsel=0; nhsel < 1; nhsel++)
|
||||
#define change_nexthops(fi) { \
|
||||
int nhsel; \
|
||||
struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \
|
||||
for (nhsel = 0; nhsel < 1; nhsel++)
|
||||
|
||||
#endif /* CONFIG_IP_ROUTE_MULTIPATH */
|
||||
|
||||
|
|
@ -86,63 +95,70 @@ static const struct
|
|||
int error;
|
||||
u8 scope;
|
||||
} fib_props[RTN_MAX + 1] = {
|
||||
{
|
||||
[RTN_UNSPEC] = {
|
||||
.error = 0,
|
||||
.scope = RT_SCOPE_NOWHERE,
|
||||
}, /* RTN_UNSPEC */
|
||||
{
|
||||
},
|
||||
[RTN_UNICAST] = {
|
||||
.error = 0,
|
||||
.scope = RT_SCOPE_UNIVERSE,
|
||||
}, /* RTN_UNICAST */
|
||||
{
|
||||
},
|
||||
[RTN_LOCAL] = {
|
||||
.error = 0,
|
||||
.scope = RT_SCOPE_HOST,
|
||||
}, /* RTN_LOCAL */
|
||||
{
|
||||
},
|
||||
[RTN_BROADCAST] = {
|
||||
.error = 0,
|
||||
.scope = RT_SCOPE_LINK,
|
||||
}, /* RTN_BROADCAST */
|
||||
{
|
||||
},
|
||||
[RTN_ANYCAST] = {
|
||||
.error = 0,
|
||||
.scope = RT_SCOPE_LINK,
|
||||
}, /* RTN_ANYCAST */
|
||||
{
|
||||
},
|
||||
[RTN_MULTICAST] = {
|
||||
.error = 0,
|
||||
.scope = RT_SCOPE_UNIVERSE,
|
||||
}, /* RTN_MULTICAST */
|
||||
{
|
||||
},
|
||||
[RTN_BLACKHOLE] = {
|
||||
.error = -EINVAL,
|
||||
.scope = RT_SCOPE_UNIVERSE,
|
||||
}, /* RTN_BLACKHOLE */
|
||||
{
|
||||
},
|
||||
[RTN_UNREACHABLE] = {
|
||||
.error = -EHOSTUNREACH,
|
||||
.scope = RT_SCOPE_UNIVERSE,
|
||||
}, /* RTN_UNREACHABLE */
|
||||
{
|
||||
},
|
||||
[RTN_PROHIBIT] = {
|
||||
.error = -EACCES,
|
||||
.scope = RT_SCOPE_UNIVERSE,
|
||||
}, /* RTN_PROHIBIT */
|
||||
{
|
||||
},
|
||||
[RTN_THROW] = {
|
||||
.error = -EAGAIN,
|
||||
.scope = RT_SCOPE_UNIVERSE,
|
||||
}, /* RTN_THROW */
|
||||
{
|
||||
},
|
||||
[RTN_NAT] = {
|
||||
.error = -EINVAL,
|
||||
.scope = RT_SCOPE_NOWHERE,
|
||||
}, /* RTN_NAT */
|
||||
{
|
||||
},
|
||||
[RTN_XRESOLVE] = {
|
||||
.error = -EINVAL,
|
||||
.scope = RT_SCOPE_NOWHERE,
|
||||
}, /* RTN_XRESOLVE */
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* Release a nexthop info record */
|
||||
|
||||
static void free_fib_info_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct fib_info *fi = container_of(head, struct fib_info, rcu);
|
||||
|
||||
kfree(fi);
|
||||
}
|
||||
|
||||
void free_fib_info(struct fib_info *fi)
|
||||
{
|
||||
if (fi->fib_dead == 0) {
|
||||
printk(KERN_WARNING "Freeing alive fib_info %p\n", fi);
|
||||
pr_warning("Freeing alive fib_info %p\n", fi);
|
||||
return;
|
||||
}
|
||||
change_nexthops(fi) {
|
||||
|
|
@ -152,7 +168,7 @@ void free_fib_info(struct fib_info *fi)
|
|||
} endfor_nexthops(fi);
|
||||
fib_info_cnt--;
|
||||
release_net(fi->fib_net);
|
||||
kfree(fi);
|
||||
call_rcu(&fi->rcu, free_fib_info_rcu);
|
||||
}
|
||||
|
||||
void fib_release_info(struct fib_info *fi)
|
||||
|
|
@ -173,7 +189,7 @@ void fib_release_info(struct fib_info *fi)
|
|||
spin_unlock_bh(&fib_info_lock);
|
||||
}
|
||||
|
||||
static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
|
||||
static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi)
|
||||
{
|
||||
const struct fib_nh *onh = ofi->fib_nh;
|
||||
|
||||
|
|
@ -187,7 +203,7 @@ static __inline__ int nh_comp(const struct fib_info *fi, const struct fib_info *
|
|||
#ifdef CONFIG_NET_CLS_ROUTE
|
||||
nh->nh_tclassid != onh->nh_tclassid ||
|
||||
#endif
|
||||
((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
|
||||
((nh->nh_flags ^ onh->nh_flags) & ~RTNH_F_DEAD))
|
||||
return -1;
|
||||
onh++;
|
||||
} endfor_nexthops(fi);
|
||||
|
|
@ -238,7 +254,7 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
|
|||
nfi->fib_priority == fi->fib_priority &&
|
||||
memcmp(nfi->fib_metrics, fi->fib_metrics,
|
||||
sizeof(fi->fib_metrics)) == 0 &&
|
||||
((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
|
||||
((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_F_DEAD) == 0 &&
|
||||
(nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
|
||||
return fi;
|
||||
}
|
||||
|
|
@ -247,9 +263,8 @@ static struct fib_info *fib_find_info(const struct fib_info *nfi)
|
|||
}
|
||||
|
||||
/* Check, that the gateway is already configured.
|
||||
Used only by redirect accept routine.
|
||||
* Used only by redirect accept routine.
|
||||
*/
|
||||
|
||||
int ip_fib_check_default(__be32 gw, struct net_device *dev)
|
||||
{
|
||||
struct hlist_head *head;
|
||||
|
|
@ -264,7 +279,7 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev)
|
|||
hlist_for_each_entry(nh, node, head, nh_hash) {
|
||||
if (nh->nh_dev == dev &&
|
||||
nh->nh_gw == gw &&
|
||||
!(nh->nh_flags&RTNH_F_DEAD)) {
|
||||
!(nh->nh_flags & RTNH_F_DEAD)) {
|
||||
spin_unlock(&fib_info_lock);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -362,10 +377,10 @@ int fib_detect_death(struct fib_info *fi, int order,
|
|||
}
|
||||
if (state == NUD_REACHABLE)
|
||||
return 0;
|
||||
if ((state&NUD_VALID) && order != dflt)
|
||||
if ((state & NUD_VALID) && order != dflt)
|
||||
return 0;
|
||||
if ((state&NUD_VALID) ||
|
||||
(*last_idx<0 && order > dflt)) {
|
||||
if ((state & NUD_VALID) ||
|
||||
(*last_idx < 0 && order > dflt)) {
|
||||
*last_resort = fi;
|
||||
*last_idx = order;
|
||||
}
|
||||
|
|
@ -476,75 +491,76 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
|
|||
|
||||
|
||||
/*
|
||||
Picture
|
||||
-------
|
||||
|
||||
Semantics of nexthop is very messy by historical reasons.
|
||||
We have to take into account, that:
|
||||
a) gateway can be actually local interface address,
|
||||
so that gatewayed route is direct.
|
||||
b) gateway must be on-link address, possibly
|
||||
described not by an ifaddr, but also by a direct route.
|
||||
c) If both gateway and interface are specified, they should not
|
||||
contradict.
|
||||
d) If we use tunnel routes, gateway could be not on-link.
|
||||
|
||||
Attempt to reconcile all of these (alas, self-contradictory) conditions
|
||||
results in pretty ugly and hairy code with obscure logic.
|
||||
|
||||
I chose to generalized it instead, so that the size
|
||||
of code does not increase practically, but it becomes
|
||||
much more general.
|
||||
Every prefix is assigned a "scope" value: "host" is local address,
|
||||
"link" is direct route,
|
||||
[ ... "site" ... "interior" ... ]
|
||||
and "universe" is true gateway route with global meaning.
|
||||
|
||||
Every prefix refers to a set of "nexthop"s (gw, oif),
|
||||
where gw must have narrower scope. This recursion stops
|
||||
when gw has LOCAL scope or if "nexthop" is declared ONLINK,
|
||||
which means that gw is forced to be on link.
|
||||
|
||||
Code is still hairy, but now it is apparently logically
|
||||
consistent and very flexible. F.e. as by-product it allows
|
||||
to co-exists in peace independent exterior and interior
|
||||
routing processes.
|
||||
|
||||
Normally it looks as following.
|
||||
|
||||
{universe prefix} -> (gw, oif) [scope link]
|
||||
|
|
||||
|-> {link prefix} -> (gw, oif) [scope local]
|
||||
|
|
||||
|-> {local prefix} (terminal node)
|
||||
* Picture
|
||||
* -------
|
||||
*
|
||||
* Semantics of nexthop is very messy by historical reasons.
|
||||
* We have to take into account, that:
|
||||
* a) gateway can be actually local interface address,
|
||||
* so that gatewayed route is direct.
|
||||
* b) gateway must be on-link address, possibly
|
||||
* described not by an ifaddr, but also by a direct route.
|
||||
* c) If both gateway and interface are specified, they should not
|
||||
* contradict.
|
||||
* d) If we use tunnel routes, gateway could be not on-link.
|
||||
*
|
||||
* Attempt to reconcile all of these (alas, self-contradictory) conditions
|
||||
* results in pretty ugly and hairy code with obscure logic.
|
||||
*
|
||||
* I chose to generalized it instead, so that the size
|
||||
* of code does not increase practically, but it becomes
|
||||
* much more general.
|
||||
* Every prefix is assigned a "scope" value: "host" is local address,
|
||||
* "link" is direct route,
|
||||
* [ ... "site" ... "interior" ... ]
|
||||
* and "universe" is true gateway route with global meaning.
|
||||
*
|
||||
* Every prefix refers to a set of "nexthop"s (gw, oif),
|
||||
* where gw must have narrower scope. This recursion stops
|
||||
* when gw has LOCAL scope or if "nexthop" is declared ONLINK,
|
||||
* which means that gw is forced to be on link.
|
||||
*
|
||||
* Code is still hairy, but now it is apparently logically
|
||||
* consistent and very flexible. F.e. as by-product it allows
|
||||
* to co-exists in peace independent exterior and interior
|
||||
* routing processes.
|
||||
*
|
||||
* Normally it looks as following.
|
||||
*
|
||||
* {universe prefix} -> (gw, oif) [scope link]
|
||||
* |
|
||||
* |-> {link prefix} -> (gw, oif) [scope local]
|
||||
* |
|
||||
* |-> {local prefix} (terminal node)
|
||||
*/
|
||||
|
||||
static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
|
||||
struct fib_nh *nh)
|
||||
{
|
||||
int err;
|
||||
struct net *net;
|
||||
struct net_device *dev;
|
||||
|
||||
net = cfg->fc_nlinfo.nl_net;
|
||||
if (nh->nh_gw) {
|
||||
struct fib_result res;
|
||||
|
||||
if (nh->nh_flags&RTNH_F_ONLINK) {
|
||||
struct net_device *dev;
|
||||
if (nh->nh_flags & RTNH_F_ONLINK) {
|
||||
|
||||
if (cfg->fc_scope >= RT_SCOPE_LINK)
|
||||
return -EINVAL;
|
||||
if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST)
|
||||
return -EINVAL;
|
||||
if ((dev = __dev_get_by_index(net, nh->nh_oif)) == NULL)
|
||||
dev = __dev_get_by_index(net, nh->nh_oif);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!(dev->flags&IFF_UP))
|
||||
if (!(dev->flags & IFF_UP))
|
||||
return -ENETDOWN;
|
||||
nh->nh_dev = dev;
|
||||
dev_hold(dev);
|
||||
nh->nh_scope = RT_SCOPE_LINK;
|
||||
return 0;
|
||||
}
|
||||
rcu_read_lock();
|
||||
{
|
||||
struct flowi fl = {
|
||||
.nl_u = {
|
||||
|
|
@ -559,50 +575,53 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
|
|||
/* 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(net, &fl, &res)) != 0)
|
||||
err = fib_lookup(net, &fl, &res);
|
||||
if (err) {
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = -EINVAL;
|
||||
if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
|
||||
goto out;
|
||||
nh->nh_scope = res.scope;
|
||||
nh->nh_oif = FIB_RES_OIF(res);
|
||||
if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
|
||||
nh->nh_dev = dev = FIB_RES_DEV(res);
|
||||
if (!dev)
|
||||
goto out;
|
||||
dev_hold(nh->nh_dev);
|
||||
err = -ENETDOWN;
|
||||
if (!(nh->nh_dev->flags & IFF_UP))
|
||||
goto out;
|
||||
err = 0;
|
||||
out:
|
||||
fib_res_put(&res);
|
||||
return err;
|
||||
dev_hold(dev);
|
||||
err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
|
||||
} else {
|
||||
struct in_device *in_dev;
|
||||
|
||||
if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
|
||||
if (nh->nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK))
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
err = -ENODEV;
|
||||
in_dev = inetdev_by_index(net, nh->nh_oif);
|
||||
if (in_dev == NULL)
|
||||
return -ENODEV;
|
||||
if (!(in_dev->dev->flags&IFF_UP)) {
|
||||
in_dev_put(in_dev);
|
||||
return -ENETDOWN;
|
||||
}
|
||||
goto out;
|
||||
err = -ENETDOWN;
|
||||
if (!(in_dev->dev->flags & IFF_UP))
|
||||
goto out;
|
||||
nh->nh_dev = in_dev->dev;
|
||||
dev_hold(nh->nh_dev);
|
||||
nh->nh_scope = RT_SCOPE_HOST;
|
||||
in_dev_put(in_dev);
|
||||
err = 0;
|
||||
}
|
||||
return 0;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline unsigned int fib_laddr_hashfn(__be32 val)
|
||||
{
|
||||
unsigned int mask = (fib_hash_size - 1);
|
||||
|
||||
return ((__force u32)val ^ ((__force u32)val >> 7) ^ ((__force u32)val >> 14)) & mask;
|
||||
return ((__force u32)val ^
|
||||
((__force u32)val >> 7) ^
|
||||
((__force u32)val >> 14)) & mask;
|
||||
}
|
||||
|
||||
static struct hlist_head *fib_hash_alloc(int bytes)
|
||||
|
|
@ -611,7 +630,8 @@ static struct hlist_head *fib_hash_alloc(int bytes)
|
|||
return kzalloc(bytes, GFP_KERNEL);
|
||||
else
|
||||
return (struct hlist_head *)
|
||||
__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(bytes));
|
||||
__get_free_pages(GFP_KERNEL | __GFP_ZERO,
|
||||
get_order(bytes));
|
||||
}
|
||||
|
||||
static void fib_hash_free(struct hlist_head *hash, int bytes)
|
||||
|
|
@ -806,7 +826,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
|
|||
goto failure;
|
||||
} else {
|
||||
change_nexthops(fi) {
|
||||
if ((err = fib_check_nh(cfg, fi, nexthop_nh)) != 0)
|
||||
err = fib_check_nh(cfg, fi, nexthop_nh);
|
||||
if (err != 0)
|
||||
goto failure;
|
||||
} endfor_nexthops(fi)
|
||||
}
|
||||
|
|
@ -819,7 +840,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
|
|||
}
|
||||
|
||||
link_it:
|
||||
if ((ofi = fib_find_info(fi)) != NULL) {
|
||||
ofi = fib_find_info(fi);
|
||||
if (ofi) {
|
||||
fi->fib_dead = 1;
|
||||
free_fib_info(fi);
|
||||
ofi->fib_treeref++;
|
||||
|
|
@ -864,7 +886,7 @@ failure:
|
|||
|
||||
/* Note! fib_semantic_match intentionally uses RCU list functions. */
|
||||
int fib_semantic_match(struct list_head *head, const struct flowi *flp,
|
||||
struct fib_result *res, int prefixlen)
|
||||
struct fib_result *res, int prefixlen, int fib_flags)
|
||||
{
|
||||
struct fib_alias *fa;
|
||||
int nh_sel = 0;
|
||||
|
|
@ -879,7 +901,7 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
|
|||
if (fa->fa_scope < flp->fl4_scope)
|
||||
continue;
|
||||
|
||||
fa->fa_state |= FA_S_ACCESSED;
|
||||
fib_alias_accessed(fa);
|
||||
|
||||
err = fib_props[fa->fa_type].error;
|
||||
if (err == 0) {
|
||||
|
|
@ -895,7 +917,7 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
|
|||
case RTN_ANYCAST:
|
||||
case RTN_MULTICAST:
|
||||
for_nexthops(fi) {
|
||||
if (nh->nh_flags&RTNH_F_DEAD)
|
||||
if (nh->nh_flags & RTNH_F_DEAD)
|
||||
continue;
|
||||
if (!flp->oif || flp->oif == nh->nh_oif)
|
||||
break;
|
||||
|
|
@ -906,16 +928,15 @@ int fib_semantic_match(struct list_head *head, const struct flowi *flp,
|
|||
goto out_fill_res;
|
||||
}
|
||||
#else
|
||||
if (nhsel < 1) {
|
||||
if (nhsel < 1)
|
||||
goto out_fill_res;
|
||||
}
|
||||
#endif
|
||||
endfor_nexthops(fi);
|
||||
continue;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "fib_semantic_match bad type %#x\n",
|
||||
fa->fa_type);
|
||||
pr_warning("fib_semantic_match bad type %#x\n",
|
||||
fa->fa_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -929,7 +950,8 @@ out_fill_res:
|
|||
res->type = fa->fa_type;
|
||||
res->scope = fa->fa_scope;
|
||||
res->fi = fa->fa_info;
|
||||
atomic_inc(&res->fi->fib_clntref);
|
||||
if (!(fib_flags & FIB_LOOKUP_NOREF))
|
||||
atomic_inc(&res->fi->fib_clntref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1028,10 +1050,10 @@ nla_put_failure:
|
|||
}
|
||||
|
||||
/*
|
||||
Update FIB if:
|
||||
- local address disappeared -> we must delete all the entries
|
||||
referring to it.
|
||||
- device went down -> we must shutdown all nexthops going via it.
|
||||
* Update FIB if:
|
||||
* - local address disappeared -> we must delete all the entries
|
||||
* referring to it.
|
||||
* - device went down -> we must shutdown all nexthops going via it.
|
||||
*/
|
||||
int fib_sync_down_addr(struct net *net, __be32 local)
|
||||
{
|
||||
|
|
@ -1078,7 +1100,7 @@ int fib_sync_down_dev(struct net_device *dev, int force)
|
|||
prev_fi = fi;
|
||||
dead = 0;
|
||||
change_nexthops(fi) {
|
||||
if (nexthop_nh->nh_flags&RTNH_F_DEAD)
|
||||
if (nexthop_nh->nh_flags & RTNH_F_DEAD)
|
||||
dead++;
|
||||
else if (nexthop_nh->nh_dev == dev &&
|
||||
nexthop_nh->nh_scope != scope) {
|
||||
|
|
@ -1110,10 +1132,9 @@ int fib_sync_down_dev(struct net_device *dev, int force)
|
|||
#ifdef CONFIG_IP_ROUTE_MULTIPATH
|
||||
|
||||
/*
|
||||
Dead device goes up. We wake up dead nexthops.
|
||||
It takes sense only on multipath routes.
|
||||
* Dead device goes up. We wake up dead nexthops.
|
||||
* It takes sense only on multipath routes.
|
||||
*/
|
||||
|
||||
int fib_sync_up(struct net_device *dev)
|
||||
{
|
||||
struct fib_info *prev_fi;
|
||||
|
|
@ -1123,7 +1144,7 @@ int fib_sync_up(struct net_device *dev)
|
|||
struct fib_nh *nh;
|
||||
int ret;
|
||||
|
||||
if (!(dev->flags&IFF_UP))
|
||||
if (!(dev->flags & IFF_UP))
|
||||
return 0;
|
||||
|
||||
prev_fi = NULL;
|
||||
|
|
@ -1142,12 +1163,12 @@ int fib_sync_up(struct net_device *dev)
|
|||
prev_fi = fi;
|
||||
alive = 0;
|
||||
change_nexthops(fi) {
|
||||
if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) {
|
||||
if (!(nexthop_nh->nh_flags & RTNH_F_DEAD)) {
|
||||
alive++;
|
||||
continue;
|
||||
}
|
||||
if (nexthop_nh->nh_dev == NULL ||
|
||||
!(nexthop_nh->nh_dev->flags&IFF_UP))
|
||||
!(nexthop_nh->nh_dev->flags & IFF_UP))
|
||||
continue;
|
||||
if (nexthop_nh->nh_dev != dev ||
|
||||
!__in_dev_get_rtnl(dev))
|
||||
|
|
@ -1169,10 +1190,9 @@ int fib_sync_up(struct net_device *dev)
|
|||
}
|
||||
|
||||
/*
|
||||
The algorithm is suboptimal, but it provides really
|
||||
fair weighted route distribution.
|
||||
* The algorithm is suboptimal, but it provides really
|
||||
* fair weighted route distribution.
|
||||
*/
|
||||
|
||||
void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
|
||||
{
|
||||
struct fib_info *fi = res->fi;
|
||||
|
|
@ -1182,7 +1202,7 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
|
|||
if (fi->fib_power <= 0) {
|
||||
int power = 0;
|
||||
change_nexthops(fi) {
|
||||
if (!(nexthop_nh->nh_flags&RTNH_F_DEAD)) {
|
||||
if (!(nexthop_nh->nh_flags & RTNH_F_DEAD)) {
|
||||
power += nexthop_nh->nh_weight;
|
||||
nexthop_nh->nh_power = nexthop_nh->nh_weight;
|
||||
}
|
||||
|
|
@ -1198,15 +1218,16 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
|
|||
|
||||
|
||||
/* w should be random number [0..fi->fib_power-1],
|
||||
it is pretty bad approximation.
|
||||
* it is pretty bad approximation.
|
||||
*/
|
||||
|
||||
w = jiffies % fi->fib_power;
|
||||
|
||||
change_nexthops(fi) {
|
||||
if (!(nexthop_nh->nh_flags&RTNH_F_DEAD) &&
|
||||
if (!(nexthop_nh->nh_flags & RTNH_F_DEAD) &&
|
||||
nexthop_nh->nh_power) {
|
||||
if ((w -= nexthop_nh->nh_power) <= 0) {
|
||||
w -= nexthop_nh->nh_power;
|
||||
if (w <= 0) {
|
||||
nexthop_nh->nh_power--;
|
||||
fi->fib_power--;
|
||||
res->nh_sel = nhsel;
|
||||
|
|
|
|||
|
|
@ -186,9 +186,7 @@ static inline struct tnode *node_parent_rcu(struct node *node)
|
|||
{
|
||||
struct tnode *ret = node_parent(node);
|
||||
|
||||
return rcu_dereference_check(ret,
|
||||
rcu_read_lock_held() ||
|
||||
lockdep_rtnl_is_held());
|
||||
return rcu_dereference_rtnl(ret);
|
||||
}
|
||||
|
||||
/* Same as rcu_assign_pointer
|
||||
|
|
@ -211,9 +209,7 @@ static inline struct node *tnode_get_child_rcu(struct tnode *tn, unsigned int i)
|
|||
{
|
||||
struct node *ret = tnode_get_child(tn, i);
|
||||
|
||||
return rcu_dereference_check(ret,
|
||||
rcu_read_lock_held() ||
|
||||
lockdep_rtnl_is_held());
|
||||
return rcu_dereference_rtnl(ret);
|
||||
}
|
||||
|
||||
static inline int tnode_child_length(const struct tnode *tn)
|
||||
|
|
@ -459,8 +455,8 @@ static struct tnode *tnode_new(t_key key, int pos, int bits)
|
|||
tn->empty_children = 1<<bits;
|
||||
}
|
||||
|
||||
pr_debug("AT %p s=%u %lu\n", tn, (unsigned int) sizeof(struct tnode),
|
||||
(unsigned long) (sizeof(struct node) << bits));
|
||||
pr_debug("AT %p s=%zu %zu\n", tn, sizeof(struct tnode),
|
||||
sizeof(struct node) << bits);
|
||||
return tn;
|
||||
}
|
||||
|
||||
|
|
@ -609,11 +605,10 @@ static struct node *resize(struct trie *t, struct tnode *tn)
|
|||
|
||||
/* Keep root node larger */
|
||||
|
||||
if (!node_parent((struct node*) tn)) {
|
||||
if (!node_parent((struct node *)tn)) {
|
||||
inflate_threshold_use = inflate_threshold_root;
|
||||
halve_threshold_use = halve_threshold_root;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
inflate_threshold_use = inflate_threshold;
|
||||
halve_threshold_use = halve_threshold;
|
||||
}
|
||||
|
|
@ -639,7 +634,7 @@ static struct node *resize(struct trie *t, struct tnode *tn)
|
|||
check_tnode(tn);
|
||||
|
||||
/* Return if at least one inflate is run */
|
||||
if( max_work != MAX_WORK)
|
||||
if (max_work != MAX_WORK)
|
||||
return (struct node *) tn;
|
||||
|
||||
/*
|
||||
|
|
@ -966,9 +961,7 @@ fib_find_node(struct trie *t, u32 key)
|
|||
struct node *n;
|
||||
|
||||
pos = 0;
|
||||
n = rcu_dereference_check(t->trie,
|
||||
rcu_read_lock_held() ||
|
||||
lockdep_rtnl_is_held());
|
||||
n = rcu_dereference_rtnl(t->trie);
|
||||
|
||||
while (n != NULL && NODE_TYPE(n) == T_TNODE) {
|
||||
tn = (struct tnode *) n;
|
||||
|
|
@ -1349,7 +1342,7 @@ err:
|
|||
/* should be called with rcu_read_lock */
|
||||
static int check_leaf(struct trie *t, struct leaf *l,
|
||||
t_key key, const struct flowi *flp,
|
||||
struct fib_result *res)
|
||||
struct fib_result *res, int fib_flags)
|
||||
{
|
||||
struct leaf_info *li;
|
||||
struct hlist_head *hhead = &l->list;
|
||||
|
|
@ -1363,7 +1356,7 @@ static int check_leaf(struct trie *t, struct leaf *l,
|
|||
if (l->key != (key & ntohl(mask)))
|
||||
continue;
|
||||
|
||||
err = fib_semantic_match(&li->falh, flp, res, plen);
|
||||
err = fib_semantic_match(&li->falh, flp, res, plen, fib_flags);
|
||||
|
||||
#ifdef CONFIG_IP_FIB_TRIE_STATS
|
||||
if (err <= 0)
|
||||
|
|
@ -1379,7 +1372,7 @@ static int check_leaf(struct trie *t, struct leaf *l,
|
|||
}
|
||||
|
||||
int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
|
||||
struct fib_result *res)
|
||||
struct fib_result *res, int fib_flags)
|
||||
{
|
||||
struct trie *t = (struct trie *) tb->tb_data;
|
||||
int ret;
|
||||
|
|
@ -1391,8 +1384,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
|
|||
t_key cindex = 0;
|
||||
int current_prefix_length = KEYLENGTH;
|
||||
struct tnode *cn;
|
||||
t_key node_prefix, key_prefix, pref_mismatch;
|
||||
int mp;
|
||||
t_key pref_mismatch;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
|
|
@ -1406,7 +1398,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
|
|||
|
||||
/* Just a leaf? */
|
||||
if (IS_LEAF(n)) {
|
||||
ret = check_leaf(t, (struct leaf *)n, key, flp, res);
|
||||
ret = check_leaf(t, (struct leaf *)n, key, flp, res, fib_flags);
|
||||
goto found;
|
||||
}
|
||||
|
||||
|
|
@ -1431,7 +1423,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
|
|||
}
|
||||
|
||||
if (IS_LEAF(n)) {
|
||||
ret = check_leaf(t, (struct leaf *)n, key, flp, res);
|
||||
ret = check_leaf(t, (struct leaf *)n, key, flp, res, fib_flags);
|
||||
if (ret > 0)
|
||||
goto backtrace;
|
||||
goto found;
|
||||
|
|
@ -1507,10 +1499,7 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
|
|||
* matching prefix.
|
||||
*/
|
||||
|
||||
node_prefix = mask_pfx(cn->key, cn->pos);
|
||||
key_prefix = mask_pfx(key, cn->pos);
|
||||
pref_mismatch = key_prefix^node_prefix;
|
||||
mp = 0;
|
||||
pref_mismatch = mask_pfx(cn->key ^ key, cn->pos);
|
||||
|
||||
/*
|
||||
* In short: If skipped bits in this node do not match
|
||||
|
|
@ -1518,13 +1507,9 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
|
|||
* state.directly.
|
||||
*/
|
||||
if (pref_mismatch) {
|
||||
while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
|
||||
mp++;
|
||||
pref_mismatch = pref_mismatch << 1;
|
||||
}
|
||||
key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
|
||||
int mp = KEYLENGTH - fls(pref_mismatch);
|
||||
|
||||
if (key_prefix != 0)
|
||||
if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0)
|
||||
goto backtrace;
|
||||
|
||||
if (current_prefix_length >= cn->pos)
|
||||
|
|
@ -1748,16 +1733,14 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct node *c)
|
|||
|
||||
/* Node empty, walk back up to parent */
|
||||
c = (struct node *) p;
|
||||
} while ( (p = node_parent_rcu(c)) != NULL);
|
||||
} while ((p = node_parent_rcu(c)) != NULL);
|
||||
|
||||
return NULL; /* Root of trie */
|
||||
}
|
||||
|
||||
static struct leaf *trie_firstleaf(struct trie *t)
|
||||
{
|
||||
struct tnode *n = (struct tnode *) rcu_dereference_check(t->trie,
|
||||
rcu_read_lock_held() ||
|
||||
lockdep_rtnl_is_held());
|
||||
struct tnode *n = (struct tnode *)rcu_dereference_rtnl(t->trie);
|
||||
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
|
@ -1855,7 +1838,8 @@ void fib_table_select_default(struct fib_table *tb,
|
|||
if (!next_fi->fib_nh[0].nh_gw ||
|
||||
next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
|
||||
continue;
|
||||
fa->fa_state |= FA_S_ACCESSED;
|
||||
|
||||
fib_alias_accessed(fa);
|
||||
|
||||
if (fi == NULL) {
|
||||
if (next_fi != res->fi)
|
||||
|
|
@ -2043,14 +2027,14 @@ struct fib_trie_iter {
|
|||
struct seq_net_private p;
|
||||
struct fib_table *tb;
|
||||
struct tnode *tnode;
|
||||
unsigned index;
|
||||
unsigned depth;
|
||||
unsigned int index;
|
||||
unsigned int depth;
|
||||
};
|
||||
|
||||
static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
|
||||
{
|
||||
struct tnode *tn = iter->tnode;
|
||||
unsigned cindex = iter->index;
|
||||
unsigned int cindex = iter->index;
|
||||
struct tnode *p;
|
||||
|
||||
/* A single entry routing table */
|
||||
|
|
@ -2159,7 +2143,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
|
|||
*/
|
||||
static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
|
||||
{
|
||||
unsigned i, max, pointers, bytes, avdepth;
|
||||
unsigned int i, max, pointers, bytes, avdepth;
|
||||
|
||||
if (stat->leaves)
|
||||
avdepth = stat->totdepth*100 / stat->leaves;
|
||||
|
|
@ -2356,7 +2340,8 @@ static void fib_trie_seq_stop(struct seq_file *seq, void *v)
|
|||
|
||||
static void seq_indent(struct seq_file *seq, int n)
|
||||
{
|
||||
while (n-- > 0) seq_puts(seq, " ");
|
||||
while (n-- > 0)
|
||||
seq_puts(seq, " ");
|
||||
}
|
||||
|
||||
static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s)
|
||||
|
|
@ -2388,7 +2373,7 @@ static const char *const rtn_type_names[__RTN_MAX] = {
|
|||
[RTN_XRESOLVE] = "XRESOLVE",
|
||||
};
|
||||
|
||||
static inline const char *rtn_type(char *buf, size_t len, unsigned t)
|
||||
static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
|
||||
{
|
||||
if (t < __RTN_MAX && rtn_type_names[t])
|
||||
return rtn_type_names[t];
|
||||
|
|
@ -2544,13 +2529,12 @@ static void fib_route_seq_stop(struct seq_file *seq, void *v)
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
|
||||
static unsigned int fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
|
||||
{
|
||||
static unsigned type2flags[RTN_MAX + 1] = {
|
||||
[7] = RTF_REJECT, [8] = RTF_REJECT,
|
||||
};
|
||||
unsigned flags = type2flags[type];
|
||||
unsigned int flags = 0;
|
||||
|
||||
if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT)
|
||||
flags = RTF_REJECT;
|
||||
if (fi && fi->fib_nh->nh_gw)
|
||||
flags |= RTF_GATEWAY;
|
||||
if (mask == htonl(0xFFFFFFFF))
|
||||
|
|
@ -2562,7 +2546,7 @@ static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
|
|||
/*
|
||||
* This outputs /proc/net/route.
|
||||
* The format of the file is not supposed to be changed
|
||||
* and needs to be same as fib_hash output to avoid breaking
|
||||
* and needs to be same as fib_hash output to avoid breaking
|
||||
* legacy utilities
|
||||
*/
|
||||
static int fib_route_seq_show(struct seq_file *seq, void *v)
|
||||
|
|
@ -2587,7 +2571,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
|
|||
|
||||
list_for_each_entry_rcu(fa, &li->falh, fa_list) {
|
||||
const struct fib_info *fi = fa->fa_info;
|
||||
unsigned flags = fib_flag_trans(fa->fa_type, mask, fi);
|
||||
unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi);
|
||||
int len;
|
||||
|
||||
if (fa->fa_type == RTN_BROADCAST
|
||||
|
|
|
|||
151
net/ipv4/gre.c
Normal file
151
net/ipv4/gre.c
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* GRE over IPv4 demultiplexer driver
|
||||
*
|
||||
* Authors: Dmitry Kozlov (xeb@mail.ru)
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/gre.h>
|
||||
|
||||
|
||||
static const struct gre_protocol *gre_proto[GREPROTO_MAX] __read_mostly;
|
||||
static DEFINE_SPINLOCK(gre_proto_lock);
|
||||
|
||||
int gre_add_protocol(const struct gre_protocol *proto, u8 version)
|
||||
{
|
||||
if (version >= GREPROTO_MAX)
|
||||
goto err_out;
|
||||
|
||||
spin_lock(&gre_proto_lock);
|
||||
if (gre_proto[version])
|
||||
goto err_out_unlock;
|
||||
|
||||
rcu_assign_pointer(gre_proto[version], proto);
|
||||
spin_unlock(&gre_proto_lock);
|
||||
return 0;
|
||||
|
||||
err_out_unlock:
|
||||
spin_unlock(&gre_proto_lock);
|
||||
err_out:
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gre_add_protocol);
|
||||
|
||||
int gre_del_protocol(const struct gre_protocol *proto, u8 version)
|
||||
{
|
||||
if (version >= GREPROTO_MAX)
|
||||
goto err_out;
|
||||
|
||||
spin_lock(&gre_proto_lock);
|
||||
if (gre_proto[version] != proto)
|
||||
goto err_out_unlock;
|
||||
rcu_assign_pointer(gre_proto[version], NULL);
|
||||
spin_unlock(&gre_proto_lock);
|
||||
synchronize_rcu();
|
||||
return 0;
|
||||
|
||||
err_out_unlock:
|
||||
spin_unlock(&gre_proto_lock);
|
||||
err_out:
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gre_del_protocol);
|
||||
|
||||
static int gre_rcv(struct sk_buff *skb)
|
||||
{
|
||||
const struct gre_protocol *proto;
|
||||
u8 ver;
|
||||
int ret;
|
||||
|
||||
if (!pskb_may_pull(skb, 12))
|
||||
goto drop;
|
||||
|
||||
ver = skb->data[1]&0x7f;
|
||||
if (ver >= GREPROTO_MAX)
|
||||
goto drop;
|
||||
|
||||
rcu_read_lock();
|
||||
proto = rcu_dereference(gre_proto[ver]);
|
||||
if (!proto || !proto->handler)
|
||||
goto drop_unlock;
|
||||
ret = proto->handler(skb);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
|
||||
drop_unlock:
|
||||
rcu_read_unlock();
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
static void gre_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
const struct gre_protocol *proto;
|
||||
u8 ver;
|
||||
|
||||
if (!pskb_may_pull(skb, 12))
|
||||
goto drop;
|
||||
|
||||
ver = skb->data[1]&0x7f;
|
||||
if (ver >= GREPROTO_MAX)
|
||||
goto drop;
|
||||
|
||||
rcu_read_lock();
|
||||
proto = rcu_dereference(gre_proto[ver]);
|
||||
if (!proto || !proto->err_handler)
|
||||
goto drop_unlock;
|
||||
proto->err_handler(skb, info);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
|
||||
drop_unlock:
|
||||
rcu_read_unlock();
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static const struct net_protocol net_gre_protocol = {
|
||||
.handler = gre_rcv,
|
||||
.err_handler = gre_err,
|
||||
.netns_ok = 1,
|
||||
};
|
||||
|
||||
static int __init gre_init(void)
|
||||
{
|
||||
pr_info("GRE over IPv4 demultiplexor driver");
|
||||
|
||||
if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
|
||||
pr_err("gre: can't add protocol\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit gre_exit(void)
|
||||
{
|
||||
inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
|
||||
}
|
||||
|
||||
module_init(gre_init);
|
||||
module_exit(gre_exit);
|
||||
|
||||
MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
|
||||
MODULE_AUTHOR("D. Kozlov ([email protected])");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
@ -379,7 +379,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
|||
inet->tos = ip_hdr(skb)->tos;
|
||||
daddr = ipc.addr = rt->rt_src;
|
||||
ipc.opt = NULL;
|
||||
ipc.shtx.flags = 0;
|
||||
ipc.tx_flags = 0;
|
||||
if (icmp_param->replyopts.optlen) {
|
||||
ipc.opt = &icmp_param->replyopts;
|
||||
if (ipc.opt->srr)
|
||||
|
|
@ -538,7 +538,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
|
|||
inet_sk(sk)->tos = tos;
|
||||
ipc.addr = iph->saddr;
|
||||
ipc.opt = &icmp_param.replyopts;
|
||||
ipc.shtx.flags = 0;
|
||||
ipc.tx_flags = 0;
|
||||
|
||||
{
|
||||
struct flowi fl = {
|
||||
|
|
|
|||
|
|
@ -1269,14 +1269,14 @@ void ip_mc_rejoin_group(struct ip_mc_list *im)
|
|||
if (im->multiaddr == IGMP_ALL_HOSTS)
|
||||
return;
|
||||
|
||||
if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
|
||||
igmp_mod_timer(im, IGMP_Initial_Report_Delay);
|
||||
return;
|
||||
}
|
||||
/* else, v3 */
|
||||
im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
|
||||
IGMP_Unsolicited_Report_Count;
|
||||
igmp_ifc_event(in_dev);
|
||||
/* a failover is happening and switches
|
||||
* must be notified immediately */
|
||||
if (IGMP_V1_SEEN(in_dev))
|
||||
igmp_send_report(in_dev, im, IGMP_HOST_MEMBERSHIP_REPORT);
|
||||
else if (IGMP_V2_SEEN(in_dev))
|
||||
igmp_send_report(in_dev, im, IGMPV2_HOST_MEMBERSHIP_REPORT);
|
||||
else
|
||||
igmp_send_report(in_dev, im, IGMPV3_HOST_MEMBERSHIP_REPORT);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(ip_mc_rejoin_group);
|
||||
|
|
@ -1418,6 +1418,7 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
|
|||
write_unlock_bh(&in_dev->mc_list_lock);
|
||||
}
|
||||
|
||||
/* RTNL is locked */
|
||||
static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
|
||||
{
|
||||
struct flowi fl = { .nl_u = { .ip4_u =
|
||||
|
|
@ -1428,15 +1429,12 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
|
|||
|
||||
if (imr->imr_ifindex) {
|
||||
idev = inetdev_by_index(net, imr->imr_ifindex);
|
||||
if (idev)
|
||||
__in_dev_put(idev);
|
||||
return idev;
|
||||
}
|
||||
if (imr->imr_address.s_addr) {
|
||||
dev = ip_dev_find(net, imr->imr_address.s_addr);
|
||||
dev = __ip_dev_find(net, imr->imr_address.s_addr, false);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
dev_put(dev);
|
||||
}
|
||||
|
||||
if (!dev && !ip_route_output_key(net, &rt, &fl)) {
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ static int inet_diag_bc_run(const void *bc, int len,
|
|||
bc += op->no;
|
||||
}
|
||||
}
|
||||
return (len == 0);
|
||||
return len == 0;
|
||||
}
|
||||
|
||||
static int valid_cc(const void *bc, int len, int cc)
|
||||
|
|
|
|||
|
|
@ -101,19 +101,43 @@ void inet_put_port(struct sock *sk)
|
|||
}
|
||||
EXPORT_SYMBOL(inet_put_port);
|
||||
|
||||
void __inet_inherit_port(struct sock *sk, struct sock *child)
|
||||
int __inet_inherit_port(struct sock *sk, struct sock *child)
|
||||
{
|
||||
struct inet_hashinfo *table = sk->sk_prot->h.hashinfo;
|
||||
const int bhash = inet_bhashfn(sock_net(sk), inet_sk(child)->inet_num,
|
||||
unsigned short port = inet_sk(child)->inet_num;
|
||||
const int bhash = inet_bhashfn(sock_net(sk), port,
|
||||
table->bhash_size);
|
||||
struct inet_bind_hashbucket *head = &table->bhash[bhash];
|
||||
struct inet_bind_bucket *tb;
|
||||
|
||||
spin_lock(&head->lock);
|
||||
tb = inet_csk(sk)->icsk_bind_hash;
|
||||
if (tb->port != port) {
|
||||
/* NOTE: using tproxy and redirecting skbs to a proxy
|
||||
* on a different listener port breaks the assumption
|
||||
* that the listener socket's icsk_bind_hash is the same
|
||||
* as that of the child socket. We have to look up or
|
||||
* create a new bind bucket for the child here. */
|
||||
struct hlist_node *node;
|
||||
inet_bind_bucket_for_each(tb, node, &head->chain) {
|
||||
if (net_eq(ib_net(tb), sock_net(sk)) &&
|
||||
tb->port == port)
|
||||
break;
|
||||
}
|
||||
if (!node) {
|
||||
tb = inet_bind_bucket_create(table->bind_bucket_cachep,
|
||||
sock_net(sk), head, port);
|
||||
if (!tb) {
|
||||
spin_unlock(&head->lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
sk_add_bind_node(child, &tb->owners);
|
||||
inet_csk(child)->icsk_bind_hash = tb;
|
||||
spin_unlock(&head->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__inet_inherit_port);
|
||||
|
||||
|
|
|
|||
|
|
@ -116,11 +116,11 @@ static int ip4_frag_match(struct inet_frag_queue *q, void *a)
|
|||
struct ip4_create_arg *arg = a;
|
||||
|
||||
qp = container_of(q, struct ipq, q);
|
||||
return (qp->id == arg->iph->id &&
|
||||
return qp->id == arg->iph->id &&
|
||||
qp->saddr == arg->iph->saddr &&
|
||||
qp->daddr == arg->iph->daddr &&
|
||||
qp->protocol == arg->iph->protocol &&
|
||||
qp->user == arg->user);
|
||||
qp->user == arg->user;
|
||||
}
|
||||
|
||||
/* Memory Tracking Functions. */
|
||||
|
|
@ -542,7 +542,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
|
|||
/* If the first fragment is fragmented itself, we split
|
||||
* it to two chunks: the first with data and paged part
|
||||
* and the second, holding only fragments. */
|
||||
if (skb_has_frags(head)) {
|
||||
if (skb_has_frag_list(head)) {
|
||||
struct sk_buff *clone;
|
||||
int i, plen = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/gre.h>
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
#include <net/ipv6.h>
|
||||
|
|
@ -63,13 +64,13 @@
|
|||
We cannot track such dead loops during route installation,
|
||||
it is infeasible task. The most general solutions would be
|
||||
to keep skb->encapsulation counter (sort of local ttl),
|
||||
and silently drop packet when it expires. It is the best
|
||||
and silently drop packet when it expires. It is a good
|
||||
solution, but it supposes maintaing new variable in ALL
|
||||
skb, even if no tunneling is used.
|
||||
|
||||
Current solution: HARD_TX_LOCK lock breaks dead loops.
|
||||
|
||||
|
||||
Current solution: xmit_recursion breaks dead loops. This is a percpu
|
||||
counter, since when we enter the first ndo_xmit(), cpu migration is
|
||||
forbidden. We force an exit if this counter reaches RECURSION_LIMIT
|
||||
|
||||
2. Networking dead loops would not kill routers, but would really
|
||||
kill network. IP hop limit plays role of "t->recursion" in this case,
|
||||
|
|
@ -128,7 +129,7 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev);
|
|||
|
||||
static int ipgre_net_id __read_mostly;
|
||||
struct ipgre_net {
|
||||
struct ip_tunnel *tunnels[4][HASH_SIZE];
|
||||
struct ip_tunnel __rcu *tunnels[4][HASH_SIZE];
|
||||
|
||||
struct net_device *fb_tunnel_dev;
|
||||
};
|
||||
|
|
@ -158,13 +159,40 @@ struct ipgre_net {
|
|||
#define tunnels_l tunnels[1]
|
||||
#define tunnels_wc tunnels[0]
|
||||
/*
|
||||
* Locking : hash tables are protected by RCU and a spinlock
|
||||
* Locking : hash tables are protected by RCU and RTNL
|
||||
*/
|
||||
static DEFINE_SPINLOCK(ipgre_lock);
|
||||
|
||||
#define for_each_ip_tunnel_rcu(start) \
|
||||
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
|
||||
|
||||
/* often modified stats are per cpu, other are shared (netdev->stats) */
|
||||
struct pcpu_tstats {
|
||||
unsigned long rx_packets;
|
||||
unsigned long rx_bytes;
|
||||
unsigned long tx_packets;
|
||||
unsigned long tx_bytes;
|
||||
};
|
||||
|
||||
static struct net_device_stats *ipgre_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct pcpu_tstats sum = { 0 };
|
||||
int i;
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
|
||||
|
||||
sum.rx_packets += tstats->rx_packets;
|
||||
sum.rx_bytes += tstats->rx_bytes;
|
||||
sum.tx_packets += tstats->tx_packets;
|
||||
sum.tx_bytes += tstats->tx_bytes;
|
||||
}
|
||||
dev->stats.rx_packets = sum.rx_packets;
|
||||
dev->stats.rx_bytes = sum.rx_bytes;
|
||||
dev->stats.tx_packets = sum.tx_packets;
|
||||
dev->stats.tx_bytes = sum.tx_bytes;
|
||||
return &dev->stats;
|
||||
}
|
||||
|
||||
/* Given src, dst and key, find appropriate for input tunnel. */
|
||||
|
||||
static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
|
||||
|
|
@ -173,8 +201,8 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
|
|||
{
|
||||
struct net *net = dev_net(dev);
|
||||
int link = dev->ifindex;
|
||||
unsigned h0 = HASH(remote);
|
||||
unsigned h1 = HASH(key);
|
||||
unsigned int h0 = HASH(remote);
|
||||
unsigned int h1 = HASH(key);
|
||||
struct ip_tunnel *t, *cand = NULL;
|
||||
struct ipgre_net *ign = net_generic(net, ipgre_net_id);
|
||||
int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
|
||||
|
|
@ -289,13 +317,13 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign,
|
||||
static struct ip_tunnel __rcu **__ipgre_bucket(struct ipgre_net *ign,
|
||||
struct ip_tunnel_parm *parms)
|
||||
{
|
||||
__be32 remote = parms->iph.daddr;
|
||||
__be32 local = parms->iph.saddr;
|
||||
__be32 key = parms->i_key;
|
||||
unsigned h = HASH(key);
|
||||
unsigned int h = HASH(key);
|
||||
int prio = 0;
|
||||
|
||||
if (local)
|
||||
|
|
@ -308,7 +336,7 @@ static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign,
|
|||
return &ign->tunnels[prio][h];
|
||||
}
|
||||
|
||||
static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign,
|
||||
static inline struct ip_tunnel __rcu **ipgre_bucket(struct ipgre_net *ign,
|
||||
struct ip_tunnel *t)
|
||||
{
|
||||
return __ipgre_bucket(ign, &t->parms);
|
||||
|
|
@ -316,23 +344,22 @@ static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign,
|
|||
|
||||
static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
|
||||
{
|
||||
struct ip_tunnel **tp = ipgre_bucket(ign, t);
|
||||
struct ip_tunnel __rcu **tp = ipgre_bucket(ign, t);
|
||||
|
||||
spin_lock_bh(&ipgre_lock);
|
||||
t->next = *tp;
|
||||
rcu_assign_pointer(t->next, rtnl_dereference(*tp));
|
||||
rcu_assign_pointer(*tp, t);
|
||||
spin_unlock_bh(&ipgre_lock);
|
||||
}
|
||||
|
||||
static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
|
||||
{
|
||||
struct ip_tunnel **tp;
|
||||
struct ip_tunnel __rcu **tp;
|
||||
struct ip_tunnel *iter;
|
||||
|
||||
for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) {
|
||||
if (t == *tp) {
|
||||
spin_lock_bh(&ipgre_lock);
|
||||
*tp = t->next;
|
||||
spin_unlock_bh(&ipgre_lock);
|
||||
for (tp = ipgre_bucket(ign, t);
|
||||
(iter = rtnl_dereference(*tp)) != NULL;
|
||||
tp = &iter->next) {
|
||||
if (t == iter) {
|
||||
rcu_assign_pointer(*tp, t->next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -346,10 +373,13 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
|
|||
__be32 local = parms->iph.saddr;
|
||||
__be32 key = parms->i_key;
|
||||
int link = parms->link;
|
||||
struct ip_tunnel *t, **tp;
|
||||
struct ip_tunnel *t;
|
||||
struct ip_tunnel __rcu **tp;
|
||||
struct ipgre_net *ign = net_generic(net, ipgre_net_id);
|
||||
|
||||
for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next)
|
||||
for (tp = __ipgre_bucket(ign, parms);
|
||||
(t = rtnl_dereference(*tp)) != NULL;
|
||||
tp = &t->next)
|
||||
if (local == t->parms.iph.saddr &&
|
||||
remote == t->parms.iph.daddr &&
|
||||
key == t->parms.i_key &&
|
||||
|
|
@ -360,7 +390,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
|
|||
return t;
|
||||
}
|
||||
|
||||
static struct ip_tunnel * ipgre_tunnel_locate(struct net *net,
|
||||
static struct ip_tunnel *ipgre_tunnel_locate(struct net *net,
|
||||
struct ip_tunnel_parm *parms, int create)
|
||||
{
|
||||
struct ip_tunnel *t, *nt;
|
||||
|
|
@ -582,7 +612,7 @@ static int ipgre_rcv(struct sk_buff *skb)
|
|||
if ((tunnel = ipgre_tunnel_lookup(skb->dev,
|
||||
iph->saddr, iph->daddr, key,
|
||||
gre_proto))) {
|
||||
struct net_device_stats *stats = &tunnel->dev->stats;
|
||||
struct pcpu_tstats *tstats;
|
||||
|
||||
secpath_reset(skb);
|
||||
|
||||
|
|
@ -606,22 +636,22 @@ static int ipgre_rcv(struct sk_buff *skb)
|
|||
/* Looped back packet, drop it! */
|
||||
if (skb_rtable(skb)->fl.iif == 0)
|
||||
goto drop;
|
||||
stats->multicast++;
|
||||
tunnel->dev->stats.multicast++;
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (((flags&GRE_CSUM) && csum) ||
|
||||
(!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
|
||||
stats->rx_crc_errors++;
|
||||
stats->rx_errors++;
|
||||
tunnel->dev->stats.rx_crc_errors++;
|
||||
tunnel->dev->stats.rx_errors++;
|
||||
goto drop;
|
||||
}
|
||||
if (tunnel->parms.i_flags&GRE_SEQ) {
|
||||
if (!(flags&GRE_SEQ) ||
|
||||
(tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
|
||||
stats->rx_fifo_errors++;
|
||||
stats->rx_errors++;
|
||||
tunnel->dev->stats.rx_fifo_errors++;
|
||||
tunnel->dev->stats.rx_errors++;
|
||||
goto drop;
|
||||
}
|
||||
tunnel->i_seqno = seqno + 1;
|
||||
|
|
@ -630,8 +660,8 @@ static int ipgre_rcv(struct sk_buff *skb)
|
|||
/* Warning: All skb pointers will be invalidated! */
|
||||
if (tunnel->dev->type == ARPHRD_ETHER) {
|
||||
if (!pskb_may_pull(skb, ETH_HLEN)) {
|
||||
stats->rx_length_errors++;
|
||||
stats->rx_errors++;
|
||||
tunnel->dev->stats.rx_length_errors++;
|
||||
tunnel->dev->stats.rx_errors++;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
|
|
@ -640,14 +670,19 @@ static int ipgre_rcv(struct sk_buff *skb)
|
|||
skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
|
||||
}
|
||||
|
||||
skb_tunnel_rx(skb, tunnel->dev);
|
||||
tstats = this_cpu_ptr(tunnel->dev->tstats);
|
||||
tstats->rx_packets++;
|
||||
tstats->rx_bytes += skb->len;
|
||||
|
||||
__skb_tunnel_rx(skb, tunnel->dev);
|
||||
|
||||
skb_reset_network_header(skb);
|
||||
ipgre_ecn_decapsulate(iph, skb);
|
||||
|
||||
netif_rx(skb);
|
||||
|
||||
rcu_read_unlock();
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
|
||||
|
||||
|
|
@ -655,20 +690,19 @@ drop:
|
|||
rcu_read_unlock();
|
||||
drop_nolock:
|
||||
kfree_skb(skb);
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct ip_tunnel *tunnel = netdev_priv(dev);
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
|
||||
struct pcpu_tstats *tstats;
|
||||
struct iphdr *old_iph = ip_hdr(skb);
|
||||
struct iphdr *tiph;
|
||||
u8 tos;
|
||||
__be16 df;
|
||||
struct rtable *rt; /* Route to the other host */
|
||||
struct net_device *tdev; /* Device to other host */
|
||||
struct net_device *tdev; /* Device to other host */
|
||||
struct iphdr *iph; /* Our new IP header */
|
||||
unsigned int max_headroom; /* The extra header space needed */
|
||||
int gre_hlen;
|
||||
|
|
@ -690,7 +724,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
|
|||
/* NBMA tunnel */
|
||||
|
||||
if (skb_dst(skb) == NULL) {
|
||||
stats->tx_fifo_errors++;
|
||||
dev->stats.tx_fifo_errors++;
|
||||
goto tx_error;
|
||||
}
|
||||
|
||||
|
|
@ -736,14 +770,20 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
|
|||
}
|
||||
|
||||
{
|
||||
struct flowi fl = { .oif = tunnel->parms.link,
|
||||
.nl_u = { .ip4_u =
|
||||
{ .daddr = dst,
|
||||
.saddr = tiph->saddr,
|
||||
.tos = RT_TOS(tos) } },
|
||||
.proto = IPPROTO_GRE };
|
||||
struct flowi fl = {
|
||||
.oif = tunnel->parms.link,
|
||||
.nl_u = {
|
||||
.ip4_u = {
|
||||
.daddr = dst,
|
||||
.saddr = tiph->saddr,
|
||||
.tos = RT_TOS(tos)
|
||||
}
|
||||
},
|
||||
.proto = IPPROTO_GRE
|
||||
}
|
||||
;
|
||||
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
|
||||
stats->tx_carrier_errors++;
|
||||
dev->stats.tx_carrier_errors++;
|
||||
goto tx_error;
|
||||
}
|
||||
}
|
||||
|
|
@ -751,7 +791,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
|
|||
|
||||
if (tdev == dev) {
|
||||
ip_rt_put(rt);
|
||||
stats->collisions++;
|
||||
dev->stats.collisions++;
|
||||
goto tx_error;
|
||||
}
|
||||
|
||||
|
|
@ -814,7 +854,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
|
|||
dev->needed_headroom = max_headroom;
|
||||
if (!new_skb) {
|
||||
ip_rt_put(rt);
|
||||
txq->tx_dropped++;
|
||||
dev->stats.tx_dropped++;
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -881,15 +921,15 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
|
|||
}
|
||||
|
||||
nf_reset(skb);
|
||||
|
||||
IPTUNNEL_XMIT();
|
||||
tstats = this_cpu_ptr(dev->tstats);
|
||||
__IPTUNNEL_XMIT(tstats, &dev->stats);
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
tx_error_icmp:
|
||||
dst_link_failure(skb);
|
||||
|
||||
tx_error:
|
||||
stats->tx_errors++;
|
||||
dev->stats.tx_errors++;
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -909,13 +949,19 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev)
|
|||
/* Guess output device to choose reasonable mtu and needed_headroom */
|
||||
|
||||
if (iph->daddr) {
|
||||
struct flowi fl = { .oif = tunnel->parms.link,
|
||||
.nl_u = { .ip4_u =
|
||||
{ .daddr = iph->daddr,
|
||||
.saddr = iph->saddr,
|
||||
.tos = RT_TOS(iph->tos) } },
|
||||
.proto = IPPROTO_GRE };
|
||||
struct flowi fl = {
|
||||
.oif = tunnel->parms.link,
|
||||
.nl_u = {
|
||||
.ip4_u = {
|
||||
.daddr = iph->daddr,
|
||||
.saddr = iph->saddr,
|
||||
.tos = RT_TOS(iph->tos)
|
||||
}
|
||||
},
|
||||
.proto = IPPROTO_GRE
|
||||
};
|
||||
struct rtable *rt;
|
||||
|
||||
if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
|
||||
tdev = rt->dst.dev;
|
||||
ip_rt_put(rt);
|
||||
|
|
@ -1012,7 +1058,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
unsigned nflags = 0;
|
||||
unsigned int nflags = 0;
|
||||
|
||||
t = netdev_priv(dev);
|
||||
|
||||
|
|
@ -1125,7 +1171,7 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
|
|||
|
||||
static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned short type,
|
||||
const void *daddr, const void *saddr, unsigned len)
|
||||
const void *daddr, const void *saddr, unsigned int len)
|
||||
{
|
||||
struct ip_tunnel *t = netdev_priv(dev);
|
||||
struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
|
||||
|
|
@ -1167,13 +1213,19 @@ static int ipgre_open(struct net_device *dev)
|
|||
struct ip_tunnel *t = netdev_priv(dev);
|
||||
|
||||
if (ipv4_is_multicast(t->parms.iph.daddr)) {
|
||||
struct flowi fl = { .oif = t->parms.link,
|
||||
.nl_u = { .ip4_u =
|
||||
{ .daddr = t->parms.iph.daddr,
|
||||
.saddr = t->parms.iph.saddr,
|
||||
.tos = RT_TOS(t->parms.iph.tos) } },
|
||||
.proto = IPPROTO_GRE };
|
||||
struct flowi fl = {
|
||||
.oif = t->parms.link,
|
||||
.nl_u = {
|
||||
.ip4_u = {
|
||||
.daddr = t->parms.iph.daddr,
|
||||
.saddr = t->parms.iph.saddr,
|
||||
.tos = RT_TOS(t->parms.iph.tos)
|
||||
}
|
||||
},
|
||||
.proto = IPPROTO_GRE
|
||||
};
|
||||
struct rtable *rt;
|
||||
|
||||
if (ip_route_output_key(dev_net(dev), &rt, &fl))
|
||||
return -EADDRNOTAVAIL;
|
||||
dev = rt->dst.dev;
|
||||
|
|
@ -1193,10 +1245,8 @@ static int ipgre_close(struct net_device *dev)
|
|||
if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
|
||||
struct in_device *in_dev;
|
||||
in_dev = inetdev_by_index(dev_net(dev), t->mlink);
|
||||
if (in_dev) {
|
||||
if (in_dev)
|
||||
ip_mc_dec_group(in_dev, t->parms.iph.daddr);
|
||||
in_dev_put(in_dev);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1213,12 +1263,19 @@ static const struct net_device_ops ipgre_netdev_ops = {
|
|||
.ndo_start_xmit = ipgre_tunnel_xmit,
|
||||
.ndo_do_ioctl = ipgre_tunnel_ioctl,
|
||||
.ndo_change_mtu = ipgre_tunnel_change_mtu,
|
||||
.ndo_get_stats = ipgre_get_stats,
|
||||
};
|
||||
|
||||
static void ipgre_dev_free(struct net_device *dev)
|
||||
{
|
||||
free_percpu(dev->tstats);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
static void ipgre_tunnel_setup(struct net_device *dev)
|
||||
{
|
||||
dev->netdev_ops = &ipgre_netdev_ops;
|
||||
dev->destructor = free_netdev;
|
||||
dev->destructor = ipgre_dev_free;
|
||||
|
||||
dev->type = ARPHRD_IPGRE;
|
||||
dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
|
||||
|
|
@ -1256,6 +1313,10 @@ static int ipgre_tunnel_init(struct net_device *dev)
|
|||
} else
|
||||
dev->header_ops = &ipgre_header_ops;
|
||||
|
||||
dev->tstats = alloc_percpu(struct pcpu_tstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1274,14 +1335,13 @@ static void ipgre_fb_tunnel_init(struct net_device *dev)
|
|||
tunnel->hlen = sizeof(struct iphdr) + 4;
|
||||
|
||||
dev_hold(dev);
|
||||
ign->tunnels_wc[0] = tunnel;
|
||||
rcu_assign_pointer(ign->tunnels_wc[0], tunnel);
|
||||
}
|
||||
|
||||
|
||||
static const struct net_protocol ipgre_protocol = {
|
||||
.handler = ipgre_rcv,
|
||||
.err_handler = ipgre_err,
|
||||
.netns_ok = 1,
|
||||
static const struct gre_protocol ipgre_protocol = {
|
||||
.handler = ipgre_rcv,
|
||||
.err_handler = ipgre_err,
|
||||
};
|
||||
|
||||
static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
|
||||
|
|
@ -1291,11 +1351,13 @@ static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
|
|||
for (prio = 0; prio < 4; prio++) {
|
||||
int h;
|
||||
for (h = 0; h < HASH_SIZE; h++) {
|
||||
struct ip_tunnel *t = ign->tunnels[prio][h];
|
||||
struct ip_tunnel *t;
|
||||
|
||||
t = rtnl_dereference(ign->tunnels[prio][h]);
|
||||
|
||||
while (t != NULL) {
|
||||
unregister_netdevice_queue(t->dev, head);
|
||||
t = t->next;
|
||||
t = rtnl_dereference(t->next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1441,6 +1503,10 @@ static int ipgre_tap_init(struct net_device *dev)
|
|||
|
||||
ipgre_tunnel_bind_dev(dev);
|
||||
|
||||
dev->tstats = alloc_percpu(struct pcpu_tstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1451,6 +1517,7 @@ static const struct net_device_ops ipgre_tap_netdev_ops = {
|
|||
.ndo_set_mac_address = eth_mac_addr,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = ipgre_tunnel_change_mtu,
|
||||
.ndo_get_stats = ipgre_get_stats,
|
||||
};
|
||||
|
||||
static void ipgre_tap_setup(struct net_device *dev)
|
||||
|
|
@ -1459,7 +1526,7 @@ static void ipgre_tap_setup(struct net_device *dev)
|
|||
ether_setup(dev);
|
||||
|
||||
dev->netdev_ops = &ipgre_tap_netdev_ops;
|
||||
dev->destructor = free_netdev;
|
||||
dev->destructor = ipgre_dev_free;
|
||||
|
||||
dev->iflink = 0;
|
||||
dev->features |= NETIF_F_NETNS_LOCAL;
|
||||
|
|
@ -1487,6 +1554,10 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nla
|
|||
if (!tb[IFLA_MTU])
|
||||
dev->mtu = mtu;
|
||||
|
||||
/* Can use a lockless transmit, unless we generate output sequences */
|
||||
if (!(nt->parms.o_flags & GRE_SEQ))
|
||||
dev->features |= NETIF_F_LLTX;
|
||||
|
||||
err = register_netdevice(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
|
@ -1522,7 +1593,7 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
|
|||
t = nt;
|
||||
|
||||
if (dev->type != ARPHRD_ETHER) {
|
||||
unsigned nflags = 0;
|
||||
unsigned int nflags = 0;
|
||||
|
||||
if (ipv4_is_multicast(p.iph.daddr))
|
||||
nflags = IFF_BROADCAST;
|
||||
|
|
@ -1663,7 +1734,7 @@ static int __init ipgre_init(void)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = inet_add_protocol(&ipgre_protocol, IPPROTO_GRE);
|
||||
err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
|
||||
if (err < 0) {
|
||||
printk(KERN_INFO "ipgre init: can't add protocol\n");
|
||||
goto add_proto_failed;
|
||||
|
|
@ -1683,7 +1754,7 @@ out:
|
|||
tap_ops_failed:
|
||||
rtnl_link_unregister(&ipgre_link_ops);
|
||||
rtnl_link_failed:
|
||||
inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
|
||||
gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
|
||||
add_proto_failed:
|
||||
unregister_pernet_device(&ipgre_net_ops);
|
||||
goto out;
|
||||
|
|
@ -1693,7 +1764,7 @@ static void __exit ipgre_fini(void)
|
|||
{
|
||||
rtnl_link_unregister(&ipgre_tap_ops);
|
||||
rtnl_link_unregister(&ipgre_link_ops);
|
||||
if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
|
||||
if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
|
||||
printk(KERN_INFO "ipgre close: can't remove protocol\n");
|
||||
unregister_pernet_device(&ipgre_net_ops);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ error:
|
|||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ip_options_compile);
|
||||
|
||||
/*
|
||||
* Undo all the changes done by ip_options_compile().
|
||||
|
|
@ -646,3 +646,4 @@ int ip_options_rcv_srr(struct sk_buff *skb)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ip_options_rcv_srr);
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|||
* LATER: this step can be merged to real generation of fragments,
|
||||
* we can switch to copy when see the first bad fragment.
|
||||
*/
|
||||
if (skb_has_frags(skb)) {
|
||||
if (skb_has_frag_list(skb)) {
|
||||
struct sk_buff *frag, *frag2;
|
||||
int first_len = skb_pagelen(skb);
|
||||
|
||||
|
|
@ -844,10 +844,9 @@ int ip_append_data(struct sock *sk,
|
|||
inet->cork.length = 0;
|
||||
sk->sk_sndmsg_page = NULL;
|
||||
sk->sk_sndmsg_off = 0;
|
||||
if ((exthdrlen = rt->dst.header_len) != 0) {
|
||||
length += exthdrlen;
|
||||
transhdrlen += exthdrlen;
|
||||
}
|
||||
exthdrlen = rt->dst.header_len;
|
||||
length += exthdrlen;
|
||||
transhdrlen += exthdrlen;
|
||||
} else {
|
||||
rt = (struct rtable *)inet->cork.dst;
|
||||
if (inet->cork.flags & IPCORK_OPT)
|
||||
|
|
@ -934,16 +933,19 @@ alloc_new_skb:
|
|||
!(rt->dst.dev->features&NETIF_F_SG))
|
||||
alloclen = mtu;
|
||||
else
|
||||
alloclen = datalen + fragheaderlen;
|
||||
alloclen = fraglen;
|
||||
|
||||
/* The last fragment gets additional space at tail.
|
||||
* Note, with MSG_MORE we overallocate on fragments,
|
||||
* because we have no idea what fragment will be
|
||||
* the last.
|
||||
*/
|
||||
if (datalen == length + fraggap)
|
||||
if (datalen == length + fraggap) {
|
||||
alloclen += rt->dst.trailer_len;
|
||||
|
||||
/* make sure mtu is not reached */
|
||||
if (datalen > mtu - fragheaderlen - rt->dst.trailer_len)
|
||||
datalen -= ALIGN(rt->dst.trailer_len, 8);
|
||||
}
|
||||
if (transhdrlen) {
|
||||
skb = sock_alloc_send_skb(sk,
|
||||
alloclen + hh_len + 15,
|
||||
|
|
@ -960,7 +962,7 @@ alloc_new_skb:
|
|||
else
|
||||
/* only the initial fragment is
|
||||
time stamped */
|
||||
ipc->shtx.flags = 0;
|
||||
ipc->tx_flags = 0;
|
||||
}
|
||||
if (skb == NULL)
|
||||
goto error;
|
||||
|
|
@ -971,7 +973,7 @@ alloc_new_skb:
|
|||
skb->ip_summed = csummode;
|
||||
skb->csum = 0;
|
||||
skb_reserve(skb, hh_len);
|
||||
*skb_tx(skb) = ipc->shtx;
|
||||
skb_shinfo(skb)->tx_flags = ipc->tx_flags;
|
||||
|
||||
/*
|
||||
* Find where to start putting bytes.
|
||||
|
|
@ -1391,7 +1393,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
|
|||
|
||||
daddr = ipc.addr = rt->rt_src;
|
||||
ipc.opt = NULL;
|
||||
ipc.shtx.flags = 0;
|
||||
ipc.tx_flags = 0;
|
||||
|
||||
if (replyopts.opt.optlen) {
|
||||
ipc.opt = &replyopts.opt;
|
||||
|
|
|
|||
210
net/ipv4/ipip.c
210
net/ipv4/ipip.c
|
|
@ -122,31 +122,59 @@
|
|||
|
||||
static int ipip_net_id __read_mostly;
|
||||
struct ipip_net {
|
||||
struct ip_tunnel *tunnels_r_l[HASH_SIZE];
|
||||
struct ip_tunnel *tunnels_r[HASH_SIZE];
|
||||
struct ip_tunnel *tunnels_l[HASH_SIZE];
|
||||
struct ip_tunnel *tunnels_wc[1];
|
||||
struct ip_tunnel **tunnels[4];
|
||||
struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE];
|
||||
struct ip_tunnel __rcu *tunnels_r[HASH_SIZE];
|
||||
struct ip_tunnel __rcu *tunnels_l[HASH_SIZE];
|
||||
struct ip_tunnel __rcu *tunnels_wc[1];
|
||||
struct ip_tunnel __rcu **tunnels[4];
|
||||
|
||||
struct net_device *fb_tunnel_dev;
|
||||
};
|
||||
|
||||
static void ipip_tunnel_init(struct net_device *dev);
|
||||
static int ipip_tunnel_init(struct net_device *dev);
|
||||
static void ipip_tunnel_setup(struct net_device *dev);
|
||||
static void ipip_dev_free(struct net_device *dev);
|
||||
|
||||
/*
|
||||
* Locking : hash tables are protected by RCU and a spinlock
|
||||
* Locking : hash tables are protected by RCU and RTNL
|
||||
*/
|
||||
static DEFINE_SPINLOCK(ipip_lock);
|
||||
|
||||
#define for_each_ip_tunnel_rcu(start) \
|
||||
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
|
||||
|
||||
/* often modified stats are per cpu, other are shared (netdev->stats) */
|
||||
struct pcpu_tstats {
|
||||
unsigned long rx_packets;
|
||||
unsigned long rx_bytes;
|
||||
unsigned long tx_packets;
|
||||
unsigned long tx_bytes;
|
||||
};
|
||||
|
||||
static struct net_device_stats *ipip_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct pcpu_tstats sum = { 0 };
|
||||
int i;
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
|
||||
|
||||
sum.rx_packets += tstats->rx_packets;
|
||||
sum.rx_bytes += tstats->rx_bytes;
|
||||
sum.tx_packets += tstats->tx_packets;
|
||||
sum.tx_bytes += tstats->tx_bytes;
|
||||
}
|
||||
dev->stats.rx_packets = sum.rx_packets;
|
||||
dev->stats.rx_bytes = sum.rx_bytes;
|
||||
dev->stats.tx_packets = sum.tx_packets;
|
||||
dev->stats.tx_bytes = sum.tx_bytes;
|
||||
return &dev->stats;
|
||||
}
|
||||
|
||||
static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
|
||||
__be32 remote, __be32 local)
|
||||
{
|
||||
unsigned h0 = HASH(remote);
|
||||
unsigned h1 = HASH(local);
|
||||
unsigned int h0 = HASH(remote);
|
||||
unsigned int h1 = HASH(local);
|
||||
struct ip_tunnel *t;
|
||||
struct ipip_net *ipn = net_generic(net, ipip_net_id);
|
||||
|
||||
|
|
@ -169,12 +197,12 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn,
|
||||
static struct ip_tunnel __rcu **__ipip_bucket(struct ipip_net *ipn,
|
||||
struct ip_tunnel_parm *parms)
|
||||
{
|
||||
__be32 remote = parms->iph.daddr;
|
||||
__be32 local = parms->iph.saddr;
|
||||
unsigned h = 0;
|
||||
unsigned int h = 0;
|
||||
int prio = 0;
|
||||
|
||||
if (remote) {
|
||||
|
|
@ -188,7 +216,7 @@ static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn,
|
|||
return &ipn->tunnels[prio][h];
|
||||
}
|
||||
|
||||
static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn,
|
||||
static inline struct ip_tunnel __rcu **ipip_bucket(struct ipip_net *ipn,
|
||||
struct ip_tunnel *t)
|
||||
{
|
||||
return __ipip_bucket(ipn, &t->parms);
|
||||
|
|
@ -196,13 +224,14 @@ static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn,
|
|||
|
||||
static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
|
||||
{
|
||||
struct ip_tunnel **tp;
|
||||
struct ip_tunnel __rcu **tp;
|
||||
struct ip_tunnel *iter;
|
||||
|
||||
for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) {
|
||||
if (t == *tp) {
|
||||
spin_lock_bh(&ipip_lock);
|
||||
*tp = t->next;
|
||||
spin_unlock_bh(&ipip_lock);
|
||||
for (tp = ipip_bucket(ipn, t);
|
||||
(iter = rtnl_dereference(*tp)) != NULL;
|
||||
tp = &iter->next) {
|
||||
if (t == iter) {
|
||||
rcu_assign_pointer(*tp, t->next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -210,12 +239,10 @@ static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
|
|||
|
||||
static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
|
||||
{
|
||||
struct ip_tunnel **tp = ipip_bucket(ipn, t);
|
||||
struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t);
|
||||
|
||||
spin_lock_bh(&ipip_lock);
|
||||
t->next = *tp;
|
||||
rcu_assign_pointer(t->next, rtnl_dereference(*tp));
|
||||
rcu_assign_pointer(*tp, t);
|
||||
spin_unlock_bh(&ipip_lock);
|
||||
}
|
||||
|
||||
static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
|
||||
|
|
@ -223,12 +250,15 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
|
|||
{
|
||||
__be32 remote = parms->iph.daddr;
|
||||
__be32 local = parms->iph.saddr;
|
||||
struct ip_tunnel *t, **tp, *nt;
|
||||
struct ip_tunnel *t, *nt;
|
||||
struct ip_tunnel __rcu **tp;
|
||||
struct net_device *dev;
|
||||
char name[IFNAMSIZ];
|
||||
struct ipip_net *ipn = net_generic(net, ipip_net_id);
|
||||
|
||||
for (tp = __ipip_bucket(ipn, parms); (t = *tp) != NULL; tp = &t->next) {
|
||||
for (tp = __ipip_bucket(ipn, parms);
|
||||
(t = rtnl_dereference(*tp)) != NULL;
|
||||
tp = &t->next) {
|
||||
if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
|
||||
return t;
|
||||
}
|
||||
|
|
@ -238,7 +268,7 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
|
|||
if (parms->name[0])
|
||||
strlcpy(name, parms->name, IFNAMSIZ);
|
||||
else
|
||||
sprintf(name, "tunl%%d");
|
||||
strcpy(name, "tunl%d");
|
||||
|
||||
dev = alloc_netdev(sizeof(*t), name, ipip_tunnel_setup);
|
||||
if (dev == NULL)
|
||||
|
|
@ -254,7 +284,8 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
|
|||
nt = netdev_priv(dev);
|
||||
nt->parms = *parms;
|
||||
|
||||
ipip_tunnel_init(dev);
|
||||
if (ipip_tunnel_init(dev) < 0)
|
||||
goto failed_free;
|
||||
|
||||
if (register_netdevice(dev) < 0)
|
||||
goto failed_free;
|
||||
|
|
@ -264,20 +295,19 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net,
|
|||
return nt;
|
||||
|
||||
failed_free:
|
||||
free_netdev(dev);
|
||||
ipip_dev_free(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* called with RTNL */
|
||||
static void ipip_tunnel_uninit(struct net_device *dev)
|
||||
{
|
||||
struct net *net = dev_net(dev);
|
||||
struct ipip_net *ipn = net_generic(net, ipip_net_id);
|
||||
|
||||
if (dev == ipn->fb_tunnel_dev) {
|
||||
spin_lock_bh(&ipip_lock);
|
||||
ipn->tunnels_wc[0] = NULL;
|
||||
spin_unlock_bh(&ipip_lock);
|
||||
} else
|
||||
if (dev == ipn->fb_tunnel_dev)
|
||||
rcu_assign_pointer(ipn->tunnels_wc[0], NULL);
|
||||
else
|
||||
ipip_tunnel_unlink(ipn, netdev_priv(dev));
|
||||
dev_put(dev);
|
||||
}
|
||||
|
|
@ -359,8 +389,10 @@ static int ipip_rcv(struct sk_buff *skb)
|
|||
const struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
rcu_read_lock();
|
||||
if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev),
|
||||
iph->saddr, iph->daddr)) != NULL) {
|
||||
tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr);
|
||||
if (tunnel != NULL) {
|
||||
struct pcpu_tstats *tstats;
|
||||
|
||||
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
|
||||
rcu_read_unlock();
|
||||
kfree_skb(skb);
|
||||
|
|
@ -374,10 +406,16 @@ static int ipip_rcv(struct sk_buff *skb)
|
|||
skb->protocol = htons(ETH_P_IP);
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
||||
skb_tunnel_rx(skb, tunnel->dev);
|
||||
tstats = this_cpu_ptr(tunnel->dev->tstats);
|
||||
tstats->rx_packets++;
|
||||
tstats->rx_bytes += skb->len;
|
||||
|
||||
__skb_tunnel_rx(skb, tunnel->dev);
|
||||
|
||||
ipip_ecn_decapsulate(iph, skb);
|
||||
|
||||
netif_rx(skb);
|
||||
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -394,13 +432,12 @@ static int ipip_rcv(struct sk_buff *skb)
|
|||
static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct ip_tunnel *tunnel = netdev_priv(dev);
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
|
||||
struct pcpu_tstats *tstats;
|
||||
struct iphdr *tiph = &tunnel->parms.iph;
|
||||
u8 tos = tunnel->parms.iph.tos;
|
||||
__be16 df = tiph->frag_off;
|
||||
struct rtable *rt; /* Route to the other host */
|
||||
struct net_device *tdev; /* Device to other host */
|
||||
struct net_device *tdev; /* Device to other host */
|
||||
struct iphdr *old_iph = ip_hdr(skb);
|
||||
struct iphdr *iph; /* Our new IP header */
|
||||
unsigned int max_headroom; /* The extra header space needed */
|
||||
|
|
@ -410,13 +447,13 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
if (skb->protocol != htons(ETH_P_IP))
|
||||
goto tx_error;
|
||||
|
||||
if (tos&1)
|
||||
if (tos & 1)
|
||||
tos = old_iph->tos;
|
||||
|
||||
if (!dst) {
|
||||
/* NBMA tunnel */
|
||||
if ((rt = skb_rtable(skb)) == NULL) {
|
||||
stats->tx_fifo_errors++;
|
||||
dev->stats.tx_fifo_errors++;
|
||||
goto tx_error;
|
||||
}
|
||||
if ((dst = rt->rt_gateway) == 0)
|
||||
|
|
@ -424,14 +461,20 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
}
|
||||
|
||||
{
|
||||
struct flowi fl = { .oif = tunnel->parms.link,
|
||||
.nl_u = { .ip4_u =
|
||||
{ .daddr = dst,
|
||||
.saddr = tiph->saddr,
|
||||
.tos = RT_TOS(tos) } },
|
||||
.proto = IPPROTO_IPIP };
|
||||
struct flowi fl = {
|
||||
.oif = tunnel->parms.link,
|
||||
.nl_u = {
|
||||
.ip4_u = {
|
||||
.daddr = dst,
|
||||
.saddr = tiph->saddr,
|
||||
.tos = RT_TOS(tos)
|
||||
}
|
||||
},
|
||||
.proto = IPPROTO_IPIP
|
||||
};
|
||||
|
||||
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
|
||||
stats->tx_carrier_errors++;
|
||||
dev->stats.tx_carrier_errors++;
|
||||
goto tx_error_icmp;
|
||||
}
|
||||
}
|
||||
|
|
@ -439,7 +482,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
if (tdev == dev) {
|
||||
ip_rt_put(rt);
|
||||
stats->collisions++;
|
||||
dev->stats.collisions++;
|
||||
goto tx_error;
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +492,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
|
||||
|
||||
if (mtu < 68) {
|
||||
stats->collisions++;
|
||||
dev->stats.collisions++;
|
||||
ip_rt_put(rt);
|
||||
goto tx_error;
|
||||
}
|
||||
|
|
@ -485,7 +528,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
|
||||
if (!new_skb) {
|
||||
ip_rt_put(rt);
|
||||
txq->tx_dropped++;
|
||||
dev->stats.tx_dropped++;
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -522,14 +565,14 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
iph->ttl = old_iph->ttl;
|
||||
|
||||
nf_reset(skb);
|
||||
|
||||
IPTUNNEL_XMIT();
|
||||
tstats = this_cpu_ptr(dev->tstats);
|
||||
__IPTUNNEL_XMIT(tstats, &dev->stats);
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
tx_error_icmp:
|
||||
dst_link_failure(skb);
|
||||
tx_error:
|
||||
stats->tx_errors++;
|
||||
dev->stats.tx_errors++;
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -544,13 +587,19 @@ static void ipip_tunnel_bind_dev(struct net_device *dev)
|
|||
iph = &tunnel->parms.iph;
|
||||
|
||||
if (iph->daddr) {
|
||||
struct flowi fl = { .oif = tunnel->parms.link,
|
||||
.nl_u = { .ip4_u =
|
||||
{ .daddr = iph->daddr,
|
||||
.saddr = iph->saddr,
|
||||
.tos = RT_TOS(iph->tos) } },
|
||||
.proto = IPPROTO_IPIP };
|
||||
struct flowi fl = {
|
||||
.oif = tunnel->parms.link,
|
||||
.nl_u = {
|
||||
.ip4_u = {
|
||||
.daddr = iph->daddr,
|
||||
.saddr = iph->saddr,
|
||||
.tos = RT_TOS(iph->tos)
|
||||
}
|
||||
},
|
||||
.proto = IPPROTO_IPIP
|
||||
};
|
||||
struct rtable *rt;
|
||||
|
||||
if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
|
||||
tdev = rt->dst.dev;
|
||||
ip_rt_put(rt);
|
||||
|
|
@ -696,13 +745,19 @@ static const struct net_device_ops ipip_netdev_ops = {
|
|||
.ndo_start_xmit = ipip_tunnel_xmit,
|
||||
.ndo_do_ioctl = ipip_tunnel_ioctl,
|
||||
.ndo_change_mtu = ipip_tunnel_change_mtu,
|
||||
|
||||
.ndo_get_stats = ipip_get_stats,
|
||||
};
|
||||
|
||||
static void ipip_dev_free(struct net_device *dev)
|
||||
{
|
||||
free_percpu(dev->tstats);
|
||||
free_netdev(dev);
|
||||
}
|
||||
|
||||
static void ipip_tunnel_setup(struct net_device *dev)
|
||||
{
|
||||
dev->netdev_ops = &ipip_netdev_ops;
|
||||
dev->destructor = free_netdev;
|
||||
dev->destructor = ipip_dev_free;
|
||||
|
||||
dev->type = ARPHRD_TUNNEL;
|
||||
dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr);
|
||||
|
|
@ -711,10 +766,11 @@ static void ipip_tunnel_setup(struct net_device *dev)
|
|||
dev->iflink = 0;
|
||||
dev->addr_len = 4;
|
||||
dev->features |= NETIF_F_NETNS_LOCAL;
|
||||
dev->features |= NETIF_F_LLTX;
|
||||
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
|
||||
}
|
||||
|
||||
static void ipip_tunnel_init(struct net_device *dev)
|
||||
static int ipip_tunnel_init(struct net_device *dev)
|
||||
{
|
||||
struct ip_tunnel *tunnel = netdev_priv(dev);
|
||||
|
||||
|
|
@ -725,9 +781,15 @@ static void ipip_tunnel_init(struct net_device *dev)
|
|||
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
|
||||
|
||||
ipip_tunnel_bind_dev(dev);
|
||||
|
||||
dev->tstats = alloc_percpu(struct pcpu_tstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __net_init ipip_fb_tunnel_init(struct net_device *dev)
|
||||
static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
|
||||
{
|
||||
struct ip_tunnel *tunnel = netdev_priv(dev);
|
||||
struct iphdr *iph = &tunnel->parms.iph;
|
||||
|
|
@ -740,11 +802,16 @@ static void __net_init ipip_fb_tunnel_init(struct net_device *dev)
|
|||
iph->protocol = IPPROTO_IPIP;
|
||||
iph->ihl = 5;
|
||||
|
||||
dev->tstats = alloc_percpu(struct pcpu_tstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_hold(dev);
|
||||
ipn->tunnels_wc[0] = tunnel;
|
||||
rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct xfrm_tunnel ipip_handler = {
|
||||
static struct xfrm_tunnel ipip_handler __read_mostly = {
|
||||
.handler = ipip_rcv,
|
||||
.err_handler = ipip_err,
|
||||
.priority = 1,
|
||||
|
|
@ -760,11 +827,12 @@ static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head)
|
|||
for (prio = 1; prio < 4; prio++) {
|
||||
int h;
|
||||
for (h = 0; h < HASH_SIZE; h++) {
|
||||
struct ip_tunnel *t = ipn->tunnels[prio][h];
|
||||
struct ip_tunnel *t;
|
||||
|
||||
t = rtnl_dereference(ipn->tunnels[prio][h]);
|
||||
while (t != NULL) {
|
||||
unregister_netdevice_queue(t->dev, head);
|
||||
t = t->next;
|
||||
t = rtnl_dereference(t->next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -789,7 +857,9 @@ static int __net_init ipip_init_net(struct net *net)
|
|||
}
|
||||
dev_net_set(ipn->fb_tunnel_dev, net);
|
||||
|
||||
ipip_fb_tunnel_init(ipn->fb_tunnel_dev);
|
||||
err = ipip_fb_tunnel_init(ipn->fb_tunnel_dev);
|
||||
if (err)
|
||||
goto err_reg_dev;
|
||||
|
||||
if ((err = register_netdev(ipn->fb_tunnel_dev)))
|
||||
goto err_reg_dev;
|
||||
|
|
@ -797,7 +867,7 @@ static int __net_init ipip_init_net(struct net *net)
|
|||
return 0;
|
||||
|
||||
err_reg_dev:
|
||||
free_netdev(ipn->fb_tunnel_dev);
|
||||
ipip_dev_free(ipn->fb_tunnel_dev);
|
||||
err_alloc_dev:
|
||||
/* nothing */
|
||||
return err;
|
||||
|
|
|
|||
428
net/ipv4/ipmr.c
428
net/ipv4/ipmr.c
File diff suppressed because it is too large
Load diff
|
|
@ -324,10 +324,10 @@ config IP_NF_TARGET_ECN
|
|||
|
||||
config IP_NF_TARGET_TTL
|
||||
tristate '"TTL" target support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
depends on NETFILTER_ADVANCED && IP_NF_MANGLE
|
||||
select NETFILTER_XT_TARGET_HL
|
||||
---help---
|
||||
This is a backwards-compat option for the user's convenience
|
||||
This is a backwards-compatible option for the user's convenience
|
||||
(e.g. when running oldconfig). It selects
|
||||
CONFIG_NETFILTER_XT_TARGET_HL.
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
|
|||
for (i = 0; i < len; i++)
|
||||
ret |= (hdr_addr[i] ^ ap->addr[i]) & ap->mask[i];
|
||||
|
||||
return (ret != 0);
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -228,7 +228,7 @@ arpt_error(struct sk_buff *skb, const struct xt_action_param *par)
|
|||
return NF_DROP;
|
||||
}
|
||||
|
||||
static inline const struct arpt_entry_target *
|
||||
static inline const struct xt_entry_target *
|
||||
arpt_get_target_c(const struct arpt_entry *e)
|
||||
{
|
||||
return arpt_get_target((struct arpt_entry *)e);
|
||||
|
|
@ -282,7 +282,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
|||
|
||||
arp = arp_hdr(skb);
|
||||
do {
|
||||
const struct arpt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
|
||||
if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
|
||||
e = arpt_next_entry(e);
|
||||
|
|
@ -297,10 +297,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
|||
if (!t->u.kernel.target->target) {
|
||||
int v;
|
||||
|
||||
v = ((struct arpt_standard_target *)t)->verdict;
|
||||
v = ((struct xt_standard_target *)t)->verdict;
|
||||
if (v < 0) {
|
||||
/* Pop from stack? */
|
||||
if (v != ARPT_RETURN) {
|
||||
if (v != XT_RETURN) {
|
||||
verdict = (unsigned)(-v) - 1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -332,7 +332,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
|||
/* Target might have changed stuff. */
|
||||
arp = arp_hdr(skb);
|
||||
|
||||
if (verdict == ARPT_CONTINUE)
|
||||
if (verdict == XT_CONTINUE)
|
||||
e = arpt_next_entry(e);
|
||||
else
|
||||
/* Verdict */
|
||||
|
|
@ -377,7 +377,7 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
|
|||
e->counters.pcnt = pos;
|
||||
|
||||
for (;;) {
|
||||
const struct arpt_standard_target *t
|
||||
const struct xt_standard_target *t
|
||||
= (void *)arpt_get_target_c(e);
|
||||
int visited = e->comefrom & (1 << hook);
|
||||
|
||||
|
|
@ -392,13 +392,13 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
|
|||
/* Unconditional return/END. */
|
||||
if ((e->target_offset == sizeof(struct arpt_entry) &&
|
||||
(strcmp(t->target.u.user.name,
|
||||
ARPT_STANDARD_TARGET) == 0) &&
|
||||
XT_STANDARD_TARGET) == 0) &&
|
||||
t->verdict < 0 && unconditional(&e->arp)) ||
|
||||
visited) {
|
||||
unsigned int oldpos, size;
|
||||
|
||||
if ((strcmp(t->target.u.user.name,
|
||||
ARPT_STANDARD_TARGET) == 0) &&
|
||||
XT_STANDARD_TARGET) == 0) &&
|
||||
t->verdict < -NF_MAX_VERDICT - 1) {
|
||||
duprintf("mark_source_chains: bad "
|
||||
"negative verdict (%i)\n",
|
||||
|
|
@ -433,7 +433,7 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
|
|||
int newpos = t->verdict;
|
||||
|
||||
if (strcmp(t->target.u.user.name,
|
||||
ARPT_STANDARD_TARGET) == 0 &&
|
||||
XT_STANDARD_TARGET) == 0 &&
|
||||
newpos >= 0) {
|
||||
if (newpos > newinfo->size -
|
||||
sizeof(struct arpt_entry)) {
|
||||
|
|
@ -464,14 +464,14 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
|
|||
|
||||
static inline int check_entry(const struct arpt_entry *e, const char *name)
|
||||
{
|
||||
const struct arpt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
|
||||
if (!arp_checkentry(&e->arp)) {
|
||||
duprintf("arp_tables: arp check failed %p %s.\n", e, name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
|
||||
if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset)
|
||||
return -EINVAL;
|
||||
|
||||
t = arpt_get_target_c(e);
|
||||
|
|
@ -483,7 +483,7 @@ static inline int check_entry(const struct arpt_entry *e, const char *name)
|
|||
|
||||
static inline int check_target(struct arpt_entry *e, const char *name)
|
||||
{
|
||||
struct arpt_entry_target *t = arpt_get_target(e);
|
||||
struct xt_entry_target *t = arpt_get_target(e);
|
||||
int ret;
|
||||
struct xt_tgchk_param par = {
|
||||
.table = name,
|
||||
|
|
@ -506,7 +506,7 @@ static inline int check_target(struct arpt_entry *e, const char *name)
|
|||
static inline int
|
||||
find_check_entry(struct arpt_entry *e, const char *name, unsigned int size)
|
||||
{
|
||||
struct arpt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct xt_target *target;
|
||||
int ret;
|
||||
|
||||
|
|
@ -536,7 +536,7 @@ out:
|
|||
|
||||
static bool check_underflow(const struct arpt_entry *e)
|
||||
{
|
||||
const struct arpt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
unsigned int verdict;
|
||||
|
||||
if (!unconditional(&e->arp))
|
||||
|
|
@ -544,7 +544,7 @@ static bool check_underflow(const struct arpt_entry *e)
|
|||
t = arpt_get_target_c(e);
|
||||
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
|
||||
return false;
|
||||
verdict = ((struct arpt_standard_target *)t)->verdict;
|
||||
verdict = ((struct xt_standard_target *)t)->verdict;
|
||||
verdict = -verdict - 1;
|
||||
return verdict == NF_DROP || verdict == NF_ACCEPT;
|
||||
}
|
||||
|
|
@ -566,7 +566,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
|
|||
}
|
||||
|
||||
if (e->next_offset
|
||||
< sizeof(struct arpt_entry) + sizeof(struct arpt_entry_target)) {
|
||||
< sizeof(struct arpt_entry) + sizeof(struct xt_entry_target)) {
|
||||
duprintf("checking: element %p size %u\n",
|
||||
e, e->next_offset);
|
||||
return -EINVAL;
|
||||
|
|
@ -598,7 +598,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
|
|||
static inline void cleanup_entry(struct arpt_entry *e)
|
||||
{
|
||||
struct xt_tgdtor_param par;
|
||||
struct arpt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
|
||||
t = arpt_get_target(e);
|
||||
par.target = t->u.kernel.target;
|
||||
|
|
@ -794,7 +794,7 @@ static int copy_entries_to_user(unsigned int total_size,
|
|||
/* FIXME: use iterator macros --RR */
|
||||
/* ... then go back and fix counters and names */
|
||||
for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
|
||||
const struct arpt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
|
||||
e = (struct arpt_entry *)(loc_cpu_entry + off);
|
||||
if (copy_to_user(userptr + off
|
||||
|
|
@ -807,7 +807,7 @@ static int copy_entries_to_user(unsigned int total_size,
|
|||
|
||||
t = arpt_get_target_c(e);
|
||||
if (copy_to_user(userptr + off + e->target_offset
|
||||
+ offsetof(struct arpt_entry_target,
|
||||
+ offsetof(struct xt_entry_target,
|
||||
u.user.name),
|
||||
t->u.kernel.target->name,
|
||||
strlen(t->u.kernel.target->name)+1) != 0) {
|
||||
|
|
@ -844,7 +844,7 @@ static int compat_calc_entry(const struct arpt_entry *e,
|
|||
const struct xt_table_info *info,
|
||||
const void *base, struct xt_table_info *newinfo)
|
||||
{
|
||||
const struct arpt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
unsigned int entry_offset;
|
||||
int off, i, ret;
|
||||
|
||||
|
|
@ -895,7 +895,7 @@ static int compat_table_info(const struct xt_table_info *info,
|
|||
static int get_info(struct net *net, void __user *user,
|
||||
const int *len, int compat)
|
||||
{
|
||||
char name[ARPT_TABLE_MAXNAMELEN];
|
||||
char name[XT_TABLE_MAXNAMELEN];
|
||||
struct xt_table *t;
|
||||
int ret;
|
||||
|
||||
|
|
@ -908,7 +908,7 @@ static int get_info(struct net *net, void __user *user,
|
|||
if (copy_from_user(name, user, sizeof(name)) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
|
||||
name[XT_TABLE_MAXNAMELEN-1] = '\0';
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (compat)
|
||||
xt_compat_lock(NFPROTO_ARP);
|
||||
|
|
@ -1204,7 +1204,7 @@ static int do_add_counters(struct net *net, const void __user *user,
|
|||
#ifdef CONFIG_COMPAT
|
||||
static inline void compat_release_entry(struct compat_arpt_entry *e)
|
||||
{
|
||||
struct arpt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
|
||||
t = compat_arpt_get_target(e);
|
||||
module_put(t->u.kernel.target->me);
|
||||
|
|
@ -1220,7 +1220,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
|
|||
const unsigned int *underflows,
|
||||
const char *name)
|
||||
{
|
||||
struct arpt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct xt_target *target;
|
||||
unsigned int entry_offset;
|
||||
int ret, off, h;
|
||||
|
|
@ -1288,7 +1288,7 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr,
|
|||
unsigned int *size, const char *name,
|
||||
struct xt_table_info *newinfo, unsigned char *base)
|
||||
{
|
||||
struct arpt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct xt_target *target;
|
||||
struct arpt_entry *de;
|
||||
unsigned int origsize;
|
||||
|
|
@ -1474,7 +1474,7 @@ out_unlock:
|
|||
}
|
||||
|
||||
struct compat_arpt_replace {
|
||||
char name[ARPT_TABLE_MAXNAMELEN];
|
||||
char name[XT_TABLE_MAXNAMELEN];
|
||||
u32 valid_hooks;
|
||||
u32 num_entries;
|
||||
u32 size;
|
||||
|
|
@ -1567,7 +1567,7 @@ static int compat_copy_entry_to_user(struct arpt_entry *e, void __user **dstptr,
|
|||
struct xt_counters *counters,
|
||||
unsigned int i)
|
||||
{
|
||||
struct arpt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct compat_arpt_entry __user *ce;
|
||||
u_int16_t target_offset, next_offset;
|
||||
compat_uint_t origsize;
|
||||
|
|
@ -1628,7 +1628,7 @@ static int compat_copy_entries_to_user(unsigned int total_size,
|
|||
}
|
||||
|
||||
struct compat_arpt_get_entries {
|
||||
char name[ARPT_TABLE_MAXNAMELEN];
|
||||
char name[XT_TABLE_MAXNAMELEN];
|
||||
compat_uint_t size;
|
||||
struct compat_arpt_entry entrytable[0];
|
||||
};
|
||||
|
|
@ -1828,7 +1828,7 @@ void arpt_unregister_table(struct xt_table *table)
|
|||
/* The built-in targets: standard (NULL) and error. */
|
||||
static struct xt_target arpt_builtin_tg[] __read_mostly = {
|
||||
{
|
||||
.name = ARPT_STANDARD_TARGET,
|
||||
.name = XT_STANDARD_TARGET,
|
||||
.targetsize = sizeof(int),
|
||||
.family = NFPROTO_ARP,
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
|
@ -1838,9 +1838,9 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = {
|
|||
#endif
|
||||
},
|
||||
{
|
||||
.name = ARPT_ERROR_TARGET,
|
||||
.name = XT_ERROR_TARGET,
|
||||
.target = arpt_error,
|
||||
.targetsize = ARPT_FUNCTION_MAXNAMELEN,
|
||||
.targetsize = XT_FUNCTION_MAXNAMELEN,
|
||||
.family = NFPROTO_ARP,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ static int checkentry(const struct xt_tgchk_param *par)
|
|||
return false;
|
||||
|
||||
if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT &&
|
||||
mangle->target != ARPT_CONTINUE)
|
||||
mangle->target != XT_CONTINUE)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ static inline bool unconditional(const struct ipt_ip *ip)
|
|||
}
|
||||
|
||||
/* for const-correctness */
|
||||
static inline const struct ipt_entry_target *
|
||||
static inline const struct xt_entry_target *
|
||||
ipt_get_target_c(const struct ipt_entry *e)
|
||||
{
|
||||
return ipt_get_target((struct ipt_entry *)e);
|
||||
|
|
@ -230,9 +230,9 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
|
|||
const char *hookname, const char **chainname,
|
||||
const char **comment, unsigned int *rulenum)
|
||||
{
|
||||
const struct ipt_standard_target *t = (void *)ipt_get_target_c(s);
|
||||
const struct xt_standard_target *t = (void *)ipt_get_target_c(s);
|
||||
|
||||
if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) {
|
||||
if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
|
||||
/* Head of user chain: ERROR target with chainname */
|
||||
*chainname = t->target.data;
|
||||
(*rulenum) = 0;
|
||||
|
|
@ -241,7 +241,7 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
|
|||
|
||||
if (s->target_offset == sizeof(struct ipt_entry) &&
|
||||
strcmp(t->target.u.kernel.target->name,
|
||||
IPT_STANDARD_TARGET) == 0 &&
|
||||
XT_STANDARD_TARGET) == 0 &&
|
||||
t->verdict < 0 &&
|
||||
unconditional(&s->ip)) {
|
||||
/* Tail of chains: STANDARD target (return/policy) */
|
||||
|
|
@ -346,7 +346,7 @@ ipt_do_table(struct sk_buff *skb,
|
|||
get_entry(table_base, private->underflow[hook]));
|
||||
|
||||
do {
|
||||
const struct ipt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
const struct xt_entry_match *ematch;
|
||||
|
||||
IP_NF_ASSERT(e);
|
||||
|
|
@ -380,10 +380,10 @@ ipt_do_table(struct sk_buff *skb,
|
|||
if (!t->u.kernel.target->target) {
|
||||
int v;
|
||||
|
||||
v = ((struct ipt_standard_target *)t)->verdict;
|
||||
v = ((struct xt_standard_target *)t)->verdict;
|
||||
if (v < 0) {
|
||||
/* Pop from stack? */
|
||||
if (v != IPT_RETURN) {
|
||||
if (v != XT_RETURN) {
|
||||
verdict = (unsigned)(-v) - 1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -421,7 +421,7 @@ ipt_do_table(struct sk_buff *skb,
|
|||
verdict = t->u.kernel.target->target(skb, &acpar);
|
||||
/* Target might have changed stuff. */
|
||||
ip = ip_hdr(skb);
|
||||
if (verdict == IPT_CONTINUE)
|
||||
if (verdict == XT_CONTINUE)
|
||||
e = ipt_next_entry(e);
|
||||
else
|
||||
/* Verdict */
|
||||
|
|
@ -461,7 +461,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
|||
e->counters.pcnt = pos;
|
||||
|
||||
for (;;) {
|
||||
const struct ipt_standard_target *t
|
||||
const struct xt_standard_target *t
|
||||
= (void *)ipt_get_target_c(e);
|
||||
int visited = e->comefrom & (1 << hook);
|
||||
|
||||
|
|
@ -475,13 +475,13 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
|||
/* Unconditional return/END. */
|
||||
if ((e->target_offset == sizeof(struct ipt_entry) &&
|
||||
(strcmp(t->target.u.user.name,
|
||||
IPT_STANDARD_TARGET) == 0) &&
|
||||
XT_STANDARD_TARGET) == 0) &&
|
||||
t->verdict < 0 && unconditional(&e->ip)) ||
|
||||
visited) {
|
||||
unsigned int oldpos, size;
|
||||
|
||||
if ((strcmp(t->target.u.user.name,
|
||||
IPT_STANDARD_TARGET) == 0) &&
|
||||
XT_STANDARD_TARGET) == 0) &&
|
||||
t->verdict < -NF_MAX_VERDICT - 1) {
|
||||
duprintf("mark_source_chains: bad "
|
||||
"negative verdict (%i)\n",
|
||||
|
|
@ -524,7 +524,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
|||
int newpos = t->verdict;
|
||||
|
||||
if (strcmp(t->target.u.user.name,
|
||||
IPT_STANDARD_TARGET) == 0 &&
|
||||
XT_STANDARD_TARGET) == 0 &&
|
||||
newpos >= 0) {
|
||||
if (newpos > newinfo->size -
|
||||
sizeof(struct ipt_entry)) {
|
||||
|
|
@ -552,7 +552,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void cleanup_match(struct ipt_entry_match *m, struct net *net)
|
||||
static void cleanup_match(struct xt_entry_match *m, struct net *net)
|
||||
{
|
||||
struct xt_mtdtor_param par;
|
||||
|
||||
|
|
@ -568,14 +568,14 @@ static void cleanup_match(struct ipt_entry_match *m, struct net *net)
|
|||
static int
|
||||
check_entry(const struct ipt_entry *e, const char *name)
|
||||
{
|
||||
const struct ipt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
|
||||
if (!ip_checkentry(&e->ip)) {
|
||||
duprintf("ip check failed %p %s.\n", e, par->match->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (e->target_offset + sizeof(struct ipt_entry_target) >
|
||||
if (e->target_offset + sizeof(struct xt_entry_target) >
|
||||
e->next_offset)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -587,7 +587,7 @@ check_entry(const struct ipt_entry *e, const char *name)
|
|||
}
|
||||
|
||||
static int
|
||||
check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
|
||||
check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
|
||||
{
|
||||
const struct ipt_ip *ip = par->entryinfo;
|
||||
int ret;
|
||||
|
|
@ -605,7 +605,7 @@ check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
|
|||
}
|
||||
|
||||
static int
|
||||
find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
|
||||
find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
|
||||
{
|
||||
struct xt_match *match;
|
||||
int ret;
|
||||
|
|
@ -630,7 +630,7 @@ err:
|
|||
|
||||
static int check_target(struct ipt_entry *e, struct net *net, const char *name)
|
||||
{
|
||||
struct ipt_entry_target *t = ipt_get_target(e);
|
||||
struct xt_entry_target *t = ipt_get_target(e);
|
||||
struct xt_tgchk_param par = {
|
||||
.net = net,
|
||||
.table = name,
|
||||
|
|
@ -656,7 +656,7 @@ static int
|
|||
find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
|
||||
unsigned int size)
|
||||
{
|
||||
struct ipt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct xt_target *target;
|
||||
int ret;
|
||||
unsigned int j;
|
||||
|
|
@ -707,7 +707,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
|
|||
|
||||
static bool check_underflow(const struct ipt_entry *e)
|
||||
{
|
||||
const struct ipt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
unsigned int verdict;
|
||||
|
||||
if (!unconditional(&e->ip))
|
||||
|
|
@ -715,7 +715,7 @@ static bool check_underflow(const struct ipt_entry *e)
|
|||
t = ipt_get_target_c(e);
|
||||
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
|
||||
return false;
|
||||
verdict = ((struct ipt_standard_target *)t)->verdict;
|
||||
verdict = ((struct xt_standard_target *)t)->verdict;
|
||||
verdict = -verdict - 1;
|
||||
return verdict == NF_DROP || verdict == NF_ACCEPT;
|
||||
}
|
||||
|
|
@ -738,7 +738,7 @@ check_entry_size_and_hooks(struct ipt_entry *e,
|
|||
}
|
||||
|
||||
if (e->next_offset
|
||||
< sizeof(struct ipt_entry) + sizeof(struct ipt_entry_target)) {
|
||||
< sizeof(struct ipt_entry) + sizeof(struct xt_entry_target)) {
|
||||
duprintf("checking: element %p size %u\n",
|
||||
e, e->next_offset);
|
||||
return -EINVAL;
|
||||
|
|
@ -771,7 +771,7 @@ static void
|
|||
cleanup_entry(struct ipt_entry *e, struct net *net)
|
||||
{
|
||||
struct xt_tgdtor_param par;
|
||||
struct ipt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct xt_entry_match *ematch;
|
||||
|
||||
/* Cleanup all matches */
|
||||
|
|
@ -972,8 +972,8 @@ copy_entries_to_user(unsigned int total_size,
|
|||
/* ... then go back and fix counters and names */
|
||||
for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
|
||||
unsigned int i;
|
||||
const struct ipt_entry_match *m;
|
||||
const struct ipt_entry_target *t;
|
||||
const struct xt_entry_match *m;
|
||||
const struct xt_entry_target *t;
|
||||
|
||||
e = (struct ipt_entry *)(loc_cpu_entry + off);
|
||||
if (copy_to_user(userptr + off
|
||||
|
|
@ -990,7 +990,7 @@ copy_entries_to_user(unsigned int total_size,
|
|||
m = (void *)e + i;
|
||||
|
||||
if (copy_to_user(userptr + off + i
|
||||
+ offsetof(struct ipt_entry_match,
|
||||
+ offsetof(struct xt_entry_match,
|
||||
u.user.name),
|
||||
m->u.kernel.match->name,
|
||||
strlen(m->u.kernel.match->name)+1)
|
||||
|
|
@ -1002,7 +1002,7 @@ copy_entries_to_user(unsigned int total_size,
|
|||
|
||||
t = ipt_get_target_c(e);
|
||||
if (copy_to_user(userptr + off + e->target_offset
|
||||
+ offsetof(struct ipt_entry_target,
|
||||
+ offsetof(struct xt_entry_target,
|
||||
u.user.name),
|
||||
t->u.kernel.target->name,
|
||||
strlen(t->u.kernel.target->name)+1) != 0) {
|
||||
|
|
@ -1040,7 +1040,7 @@ static int compat_calc_entry(const struct ipt_entry *e,
|
|||
const void *base, struct xt_table_info *newinfo)
|
||||
{
|
||||
const struct xt_entry_match *ematch;
|
||||
const struct ipt_entry_target *t;
|
||||
const struct xt_entry_target *t;
|
||||
unsigned int entry_offset;
|
||||
int off, i, ret;
|
||||
|
||||
|
|
@ -1092,7 +1092,7 @@ static int compat_table_info(const struct xt_table_info *info,
|
|||
static int get_info(struct net *net, void __user *user,
|
||||
const int *len, int compat)
|
||||
{
|
||||
char name[IPT_TABLE_MAXNAMELEN];
|
||||
char name[XT_TABLE_MAXNAMELEN];
|
||||
struct xt_table *t;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1105,7 +1105,7 @@ static int get_info(struct net *net, void __user *user,
|
|||
if (copy_from_user(name, user, sizeof(name)) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
name[IPT_TABLE_MAXNAMELEN-1] = '\0';
|
||||
name[XT_TABLE_MAXNAMELEN-1] = '\0';
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (compat)
|
||||
xt_compat_lock(AF_INET);
|
||||
|
|
@ -1400,14 +1400,14 @@ do_add_counters(struct net *net, const void __user *user,
|
|||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_ipt_replace {
|
||||
char name[IPT_TABLE_MAXNAMELEN];
|
||||
char name[XT_TABLE_MAXNAMELEN];
|
||||
u32 valid_hooks;
|
||||
u32 num_entries;
|
||||
u32 size;
|
||||
u32 hook_entry[NF_INET_NUMHOOKS];
|
||||
u32 underflow[NF_INET_NUMHOOKS];
|
||||
u32 num_counters;
|
||||
compat_uptr_t counters; /* struct ipt_counters * */
|
||||
compat_uptr_t counters; /* struct xt_counters * */
|
||||
struct compat_ipt_entry entries[0];
|
||||
};
|
||||
|
||||
|
|
@ -1416,7 +1416,7 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
|
|||
unsigned int *size, struct xt_counters *counters,
|
||||
unsigned int i)
|
||||
{
|
||||
struct ipt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct compat_ipt_entry __user *ce;
|
||||
u_int16_t target_offset, next_offset;
|
||||
compat_uint_t origsize;
|
||||
|
|
@ -1451,7 +1451,7 @@ compat_copy_entry_to_user(struct ipt_entry *e, void __user **dstptr,
|
|||
}
|
||||
|
||||
static int
|
||||
compat_find_calc_match(struct ipt_entry_match *m,
|
||||
compat_find_calc_match(struct xt_entry_match *m,
|
||||
const char *name,
|
||||
const struct ipt_ip *ip,
|
||||
unsigned int hookmask,
|
||||
|
|
@ -1473,7 +1473,7 @@ compat_find_calc_match(struct ipt_entry_match *m,
|
|||
|
||||
static void compat_release_entry(struct compat_ipt_entry *e)
|
||||
{
|
||||
struct ipt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct xt_entry_match *ematch;
|
||||
|
||||
/* Cleanup all matches */
|
||||
|
|
@ -1494,7 +1494,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
|
|||
const char *name)
|
||||
{
|
||||
struct xt_entry_match *ematch;
|
||||
struct ipt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct xt_target *target;
|
||||
unsigned int entry_offset;
|
||||
unsigned int j;
|
||||
|
|
@ -1576,7 +1576,7 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr,
|
|||
unsigned int *size, const char *name,
|
||||
struct xt_table_info *newinfo, unsigned char *base)
|
||||
{
|
||||
struct ipt_entry_target *t;
|
||||
struct xt_entry_target *t;
|
||||
struct xt_target *target;
|
||||
struct ipt_entry *de;
|
||||
unsigned int origsize;
|
||||
|
|
@ -1884,7 +1884,7 @@ compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
|
|||
}
|
||||
|
||||
struct compat_ipt_get_entries {
|
||||
char name[IPT_TABLE_MAXNAMELEN];
|
||||
char name[XT_TABLE_MAXNAMELEN];
|
||||
compat_uint_t size;
|
||||
struct compat_ipt_entry entrytable[0];
|
||||
};
|
||||
|
|
@ -2039,7 +2039,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
|
|||
|
||||
case IPT_SO_GET_REVISION_MATCH:
|
||||
case IPT_SO_GET_REVISION_TARGET: {
|
||||
struct ipt_get_revision rev;
|
||||
struct xt_get_revision rev;
|
||||
int target;
|
||||
|
||||
if (*len != sizeof(rev)) {
|
||||
|
|
@ -2176,7 +2176,7 @@ static int icmp_checkentry(const struct xt_mtchk_param *par)
|
|||
|
||||
static struct xt_target ipt_builtin_tg[] __read_mostly = {
|
||||
{
|
||||
.name = IPT_STANDARD_TARGET,
|
||||
.name = XT_STANDARD_TARGET,
|
||||
.targetsize = sizeof(int),
|
||||
.family = NFPROTO_IPV4,
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
|
@ -2186,9 +2186,9 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = {
|
|||
#endif
|
||||
},
|
||||
{
|
||||
.name = IPT_ERROR_TARGET,
|
||||
.name = XT_ERROR_TARGET,
|
||||
.target = ipt_error,
|
||||
.targetsize = IPT_FUNCTION_MAXNAMELEN,
|
||||
.targetsize = XT_FUNCTION_MAXNAMELEN,
|
||||
.family = NFPROTO_IPV4,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#define CLUSTERIP_VERSION "0.8"
|
||||
|
||||
|
|
@ -231,24 +232,22 @@ clusterip_hashfn(const struct sk_buff *skb,
|
|||
{
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
unsigned long hashval;
|
||||
u_int16_t sport, dport;
|
||||
const u_int16_t *ports;
|
||||
u_int16_t sport = 0, dport = 0;
|
||||
int poff;
|
||||
|
||||
switch (iph->protocol) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
case IPPROTO_SCTP:
|
||||
case IPPROTO_DCCP:
|
||||
case IPPROTO_ICMP:
|
||||
ports = (const void *)iph+iph->ihl*4;
|
||||
sport = ports[0];
|
||||
dport = ports[1];
|
||||
break;
|
||||
default:
|
||||
poff = proto_ports_offset(iph->protocol);
|
||||
if (poff >= 0) {
|
||||
const u_int16_t *ports;
|
||||
u16 _ports[2];
|
||||
|
||||
ports = skb_header_pointer(skb, iph->ihl * 4 + poff, 4, _ports);
|
||||
if (ports) {
|
||||
sport = ports[0];
|
||||
dport = ports[1];
|
||||
}
|
||||
} else {
|
||||
if (net_ratelimit())
|
||||
pr_info("unknown protocol %u\n", iph->protocol);
|
||||
sport = dport = 0;
|
||||
}
|
||||
|
||||
switch (config->hash_mode) {
|
||||
|
|
|
|||
|
|
@ -24,16 +24,15 @@
|
|||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv4/ipt_LOG.h>
|
||||
#include <net/netfilter/nf_log.h>
|
||||
#include <net/netfilter/xt_log.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Netfilter Core Team <[email protected]>");
|
||||
MODULE_DESCRIPTION("Xtables: IPv4 packet logging to syslog");
|
||||
|
||||
/* Use lock to serialize, so printks don't overlap */
|
||||
static DEFINE_SPINLOCK(log_lock);
|
||||
|
||||
/* One level of recursion won't kill us */
|
||||
static void dump_packet(const struct nf_loginfo *info,
|
||||
static void dump_packet(struct sbuff *m,
|
||||
const struct nf_loginfo *info,
|
||||
const struct sk_buff *skb,
|
||||
unsigned int iphoff)
|
||||
{
|
||||
|
|
@ -48,32 +47,32 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
|
||||
ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
|
||||
if (ih == NULL) {
|
||||
printk("TRUNCATED");
|
||||
sb_add(m, "TRUNCATED");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Important fields:
|
||||
* TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
|
||||
/* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
|
||||
printk("SRC=%pI4 DST=%pI4 ",
|
||||
sb_add(m, "SRC=%pI4 DST=%pI4 ",
|
||||
&ih->saddr, &ih->daddr);
|
||||
|
||||
/* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
|
||||
printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
|
||||
sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
|
||||
ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
|
||||
ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
|
||||
|
||||
/* Max length: 6 "CE DF MF " */
|
||||
if (ntohs(ih->frag_off) & IP_CE)
|
||||
printk("CE ");
|
||||
sb_add(m, "CE ");
|
||||
if (ntohs(ih->frag_off) & IP_DF)
|
||||
printk("DF ");
|
||||
sb_add(m, "DF ");
|
||||
if (ntohs(ih->frag_off) & IP_MF)
|
||||
printk("MF ");
|
||||
sb_add(m, "MF ");
|
||||
|
||||
/* Max length: 11 "FRAG:65535 " */
|
||||
if (ntohs(ih->frag_off) & IP_OFFSET)
|
||||
printk("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
|
||||
sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
|
||||
|
||||
if ((logflags & IPT_LOG_IPOPT) &&
|
||||
ih->ihl * 4 > sizeof(struct iphdr)) {
|
||||
|
|
@ -85,15 +84,15 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
op = skb_header_pointer(skb, iphoff+sizeof(_iph),
|
||||
optsize, _opt);
|
||||
if (op == NULL) {
|
||||
printk("TRUNCATED");
|
||||
sb_add(m, "TRUNCATED");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Max length: 127 "OPT (" 15*4*2chars ") " */
|
||||
printk("OPT (");
|
||||
sb_add(m, "OPT (");
|
||||
for (i = 0; i < optsize; i++)
|
||||
printk("%02X", op[i]);
|
||||
printk(") ");
|
||||
sb_add(m, "%02X", op[i]);
|
||||
sb_add(m, ") ");
|
||||
}
|
||||
|
||||
switch (ih->protocol) {
|
||||
|
|
@ -102,7 +101,7 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
const struct tcphdr *th;
|
||||
|
||||
/* Max length: 10 "PROTO=TCP " */
|
||||
printk("PROTO=TCP ");
|
||||
sb_add(m, "PROTO=TCP ");
|
||||
|
||||
if (ntohs(ih->frag_off) & IP_OFFSET)
|
||||
break;
|
||||
|
|
@ -111,41 +110,41 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
th = skb_header_pointer(skb, iphoff + ih->ihl * 4,
|
||||
sizeof(_tcph), &_tcph);
|
||||
if (th == NULL) {
|
||||
printk("INCOMPLETE [%u bytes] ",
|
||||
sb_add(m, "INCOMPLETE [%u bytes] ",
|
||||
skb->len - iphoff - ih->ihl*4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Max length: 20 "SPT=65535 DPT=65535 " */
|
||||
printk("SPT=%u DPT=%u ",
|
||||
sb_add(m, "SPT=%u DPT=%u ",
|
||||
ntohs(th->source), ntohs(th->dest));
|
||||
/* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
|
||||
if (logflags & IPT_LOG_TCPSEQ)
|
||||
printk("SEQ=%u ACK=%u ",
|
||||
sb_add(m, "SEQ=%u ACK=%u ",
|
||||
ntohl(th->seq), ntohl(th->ack_seq));
|
||||
/* Max length: 13 "WINDOW=65535 " */
|
||||
printk("WINDOW=%u ", ntohs(th->window));
|
||||
sb_add(m, "WINDOW=%u ", ntohs(th->window));
|
||||
/* Max length: 9 "RES=0x3F " */
|
||||
printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
|
||||
sb_add(m, "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
|
||||
/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
|
||||
if (th->cwr)
|
||||
printk("CWR ");
|
||||
sb_add(m, "CWR ");
|
||||
if (th->ece)
|
||||
printk("ECE ");
|
||||
sb_add(m, "ECE ");
|
||||
if (th->urg)
|
||||
printk("URG ");
|
||||
sb_add(m, "URG ");
|
||||
if (th->ack)
|
||||
printk("ACK ");
|
||||
sb_add(m, "ACK ");
|
||||
if (th->psh)
|
||||
printk("PSH ");
|
||||
sb_add(m, "PSH ");
|
||||
if (th->rst)
|
||||
printk("RST ");
|
||||
sb_add(m, "RST ");
|
||||
if (th->syn)
|
||||
printk("SYN ");
|
||||
sb_add(m, "SYN ");
|
||||
if (th->fin)
|
||||
printk("FIN ");
|
||||
sb_add(m, "FIN ");
|
||||
/* Max length: 11 "URGP=65535 " */
|
||||
printk("URGP=%u ", ntohs(th->urg_ptr));
|
||||
sb_add(m, "URGP=%u ", ntohs(th->urg_ptr));
|
||||
|
||||
if ((logflags & IPT_LOG_TCPOPT) &&
|
||||
th->doff * 4 > sizeof(struct tcphdr)) {
|
||||
|
|
@ -158,15 +157,15 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
iphoff+ih->ihl*4+sizeof(_tcph),
|
||||
optsize, _opt);
|
||||
if (op == NULL) {
|
||||
printk("TRUNCATED");
|
||||
sb_add(m, "TRUNCATED");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Max length: 127 "OPT (" 15*4*2chars ") " */
|
||||
printk("OPT (");
|
||||
sb_add(m, "OPT (");
|
||||
for (i = 0; i < optsize; i++)
|
||||
printk("%02X", op[i]);
|
||||
printk(") ");
|
||||
sb_add(m, "%02X", op[i]);
|
||||
sb_add(m, ") ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -177,9 +176,9 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
|
||||
if (ih->protocol == IPPROTO_UDP)
|
||||
/* Max length: 10 "PROTO=UDP " */
|
||||
printk("PROTO=UDP " );
|
||||
sb_add(m, "PROTO=UDP " );
|
||||
else /* Max length: 14 "PROTO=UDPLITE " */
|
||||
printk("PROTO=UDPLITE ");
|
||||
sb_add(m, "PROTO=UDPLITE ");
|
||||
|
||||
if (ntohs(ih->frag_off) & IP_OFFSET)
|
||||
break;
|
||||
|
|
@ -188,13 +187,13 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
uh = skb_header_pointer(skb, iphoff+ih->ihl*4,
|
||||
sizeof(_udph), &_udph);
|
||||
if (uh == NULL) {
|
||||
printk("INCOMPLETE [%u bytes] ",
|
||||
sb_add(m, "INCOMPLETE [%u bytes] ",
|
||||
skb->len - iphoff - ih->ihl*4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Max length: 20 "SPT=65535 DPT=65535 " */
|
||||
printk("SPT=%u DPT=%u LEN=%u ",
|
||||
sb_add(m, "SPT=%u DPT=%u LEN=%u ",
|
||||
ntohs(uh->source), ntohs(uh->dest),
|
||||
ntohs(uh->len));
|
||||
break;
|
||||
|
|
@ -221,7 +220,7 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
[ICMP_ADDRESSREPLY] = 12 };
|
||||
|
||||
/* Max length: 11 "PROTO=ICMP " */
|
||||
printk("PROTO=ICMP ");
|
||||
sb_add(m, "PROTO=ICMP ");
|
||||
|
||||
if (ntohs(ih->frag_off) & IP_OFFSET)
|
||||
break;
|
||||
|
|
@ -230,19 +229,19 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
|
||||
sizeof(_icmph), &_icmph);
|
||||
if (ich == NULL) {
|
||||
printk("INCOMPLETE [%u bytes] ",
|
||||
sb_add(m, "INCOMPLETE [%u bytes] ",
|
||||
skb->len - iphoff - ih->ihl*4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Max length: 18 "TYPE=255 CODE=255 " */
|
||||
printk("TYPE=%u CODE=%u ", ich->type, ich->code);
|
||||
sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code);
|
||||
|
||||
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
|
||||
if (ich->type <= NR_ICMP_TYPES &&
|
||||
required_len[ich->type] &&
|
||||
skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
|
||||
printk("INCOMPLETE [%u bytes] ",
|
||||
sb_add(m, "INCOMPLETE [%u bytes] ",
|
||||
skb->len - iphoff - ih->ihl*4);
|
||||
break;
|
||||
}
|
||||
|
|
@ -251,35 +250,35 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
case ICMP_ECHOREPLY:
|
||||
case ICMP_ECHO:
|
||||
/* Max length: 19 "ID=65535 SEQ=65535 " */
|
||||
printk("ID=%u SEQ=%u ",
|
||||
sb_add(m, "ID=%u SEQ=%u ",
|
||||
ntohs(ich->un.echo.id),
|
||||
ntohs(ich->un.echo.sequence));
|
||||
break;
|
||||
|
||||
case ICMP_PARAMETERPROB:
|
||||
/* Max length: 14 "PARAMETER=255 " */
|
||||
printk("PARAMETER=%u ",
|
||||
sb_add(m, "PARAMETER=%u ",
|
||||
ntohl(ich->un.gateway) >> 24);
|
||||
break;
|
||||
case ICMP_REDIRECT:
|
||||
/* Max length: 24 "GATEWAY=255.255.255.255 " */
|
||||
printk("GATEWAY=%pI4 ", &ich->un.gateway);
|
||||
sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway);
|
||||
/* Fall through */
|
||||
case ICMP_DEST_UNREACH:
|
||||
case ICMP_SOURCE_QUENCH:
|
||||
case ICMP_TIME_EXCEEDED:
|
||||
/* Max length: 3+maxlen */
|
||||
if (!iphoff) { /* Only recurse once. */
|
||||
printk("[");
|
||||
dump_packet(info, skb,
|
||||
sb_add(m, "[");
|
||||
dump_packet(m, info, skb,
|
||||
iphoff + ih->ihl*4+sizeof(_icmph));
|
||||
printk("] ");
|
||||
sb_add(m, "] ");
|
||||
}
|
||||
|
||||
/* Max length: 10 "MTU=65535 " */
|
||||
if (ich->type == ICMP_DEST_UNREACH &&
|
||||
ich->code == ICMP_FRAG_NEEDED)
|
||||
printk("MTU=%u ", ntohs(ich->un.frag.mtu));
|
||||
sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -292,19 +291,19 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
break;
|
||||
|
||||
/* Max length: 9 "PROTO=AH " */
|
||||
printk("PROTO=AH ");
|
||||
sb_add(m, "PROTO=AH ");
|
||||
|
||||
/* Max length: 25 "INCOMPLETE [65535 bytes] " */
|
||||
ah = skb_header_pointer(skb, iphoff+ih->ihl*4,
|
||||
sizeof(_ahdr), &_ahdr);
|
||||
if (ah == NULL) {
|
||||
printk("INCOMPLETE [%u bytes] ",
|
||||
sb_add(m, "INCOMPLETE [%u bytes] ",
|
||||
skb->len - iphoff - ih->ihl*4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Length: 15 "SPI=0xF1234567 " */
|
||||
printk("SPI=0x%x ", ntohl(ah->spi));
|
||||
sb_add(m, "SPI=0x%x ", ntohl(ah->spi));
|
||||
break;
|
||||
}
|
||||
case IPPROTO_ESP: {
|
||||
|
|
@ -312,7 +311,7 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
const struct ip_esp_hdr *eh;
|
||||
|
||||
/* Max length: 10 "PROTO=ESP " */
|
||||
printk("PROTO=ESP ");
|
||||
sb_add(m, "PROTO=ESP ");
|
||||
|
||||
if (ntohs(ih->frag_off) & IP_OFFSET)
|
||||
break;
|
||||
|
|
@ -321,25 +320,25 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
eh = skb_header_pointer(skb, iphoff+ih->ihl*4,
|
||||
sizeof(_esph), &_esph);
|
||||
if (eh == NULL) {
|
||||
printk("INCOMPLETE [%u bytes] ",
|
||||
sb_add(m, "INCOMPLETE [%u bytes] ",
|
||||
skb->len - iphoff - ih->ihl*4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Length: 15 "SPI=0xF1234567 " */
|
||||
printk("SPI=0x%x ", ntohl(eh->spi));
|
||||
sb_add(m, "SPI=0x%x ", ntohl(eh->spi));
|
||||
break;
|
||||
}
|
||||
/* Max length: 10 "PROTO 255 " */
|
||||
default:
|
||||
printk("PROTO=%u ", ih->protocol);
|
||||
sb_add(m, "PROTO=%u ", ih->protocol);
|
||||
}
|
||||
|
||||
/* Max length: 15 "UID=4294967295 " */
|
||||
if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) {
|
||||
read_lock_bh(&skb->sk->sk_callback_lock);
|
||||
if (skb->sk->sk_socket && skb->sk->sk_socket->file)
|
||||
printk("UID=%u GID=%u ",
|
||||
sb_add(m, "UID=%u GID=%u ",
|
||||
skb->sk->sk_socket->file->f_cred->fsuid,
|
||||
skb->sk->sk_socket->file->f_cred->fsgid);
|
||||
read_unlock_bh(&skb->sk->sk_callback_lock);
|
||||
|
|
@ -347,7 +346,7 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
|
||||
/* Max length: 16 "MARK=0xFFFFFFFF " */
|
||||
if (!iphoff && skb->mark)
|
||||
printk("MARK=0x%x ", skb->mark);
|
||||
sb_add(m, "MARK=0x%x ", skb->mark);
|
||||
|
||||
/* Proto Max log string length */
|
||||
/* IP: 40+46+6+11+127 = 230 */
|
||||
|
|
@ -364,7 +363,8 @@ static void dump_packet(const struct nf_loginfo *info,
|
|||
/* maxlen = 230+ 91 + 230 + 252 = 803 */
|
||||
}
|
||||
|
||||
static void dump_mac_header(const struct nf_loginfo *info,
|
||||
static void dump_mac_header(struct sbuff *m,
|
||||
const struct nf_loginfo *info,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb->dev;
|
||||
|
|
@ -378,7 +378,7 @@ static void dump_mac_header(const struct nf_loginfo *info,
|
|||
|
||||
switch (dev->type) {
|
||||
case ARPHRD_ETHER:
|
||||
printk("MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
|
||||
sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
|
||||
eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
|
||||
ntohs(eth_hdr(skb)->h_proto));
|
||||
return;
|
||||
|
|
@ -387,17 +387,17 @@ static void dump_mac_header(const struct nf_loginfo *info,
|
|||
}
|
||||
|
||||
fallback:
|
||||
printk("MAC=");
|
||||
sb_add(m, "MAC=");
|
||||
if (dev->hard_header_len &&
|
||||
skb->mac_header != skb->network_header) {
|
||||
const unsigned char *p = skb_mac_header(skb);
|
||||
unsigned int i;
|
||||
|
||||
printk("%02x", *p++);
|
||||
sb_add(m, "%02x", *p++);
|
||||
for (i = 1; i < dev->hard_header_len; i++, p++)
|
||||
printk(":%02x", *p);
|
||||
sb_add(m, ":%02x", *p);
|
||||
}
|
||||
printk(" ");
|
||||
sb_add(m, " ");
|
||||
}
|
||||
|
||||
static struct nf_loginfo default_loginfo = {
|
||||
|
|
@ -419,11 +419,12 @@ ipt_log_packet(u_int8_t pf,
|
|||
const struct nf_loginfo *loginfo,
|
||||
const char *prefix)
|
||||
{
|
||||
struct sbuff *m = sb_open();
|
||||
|
||||
if (!loginfo)
|
||||
loginfo = &default_loginfo;
|
||||
|
||||
spin_lock_bh(&log_lock);
|
||||
printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
|
||||
sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
|
||||
prefix,
|
||||
in ? in->name : "",
|
||||
out ? out->name : "");
|
||||
|
|
@ -434,20 +435,20 @@ ipt_log_packet(u_int8_t pf,
|
|||
|
||||
physindev = skb->nf_bridge->physindev;
|
||||
if (physindev && in != physindev)
|
||||
printk("PHYSIN=%s ", physindev->name);
|
||||
sb_add(m, "PHYSIN=%s ", physindev->name);
|
||||
physoutdev = skb->nf_bridge->physoutdev;
|
||||
if (physoutdev && out != physoutdev)
|
||||
printk("PHYSOUT=%s ", physoutdev->name);
|
||||
sb_add(m, "PHYSOUT=%s ", physoutdev->name);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* MAC logging for input path only. */
|
||||
if (in && !out)
|
||||
dump_mac_header(loginfo, skb);
|
||||
dump_mac_header(m, loginfo, skb);
|
||||
|
||||
dump_packet(loginfo, skb, 0);
|
||||
printk("\n");
|
||||
spin_unlock_bh(&log_lock);
|
||||
dump_packet(m, loginfo, skb, 0);
|
||||
|
||||
sb_close(m);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
|
|
|
|||
|
|
@ -44,9 +44,16 @@ static unsigned int help(struct sk_buff *skb,
|
|||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
|
||||
int ret;
|
||||
|
||||
exp->tuple.dst.u.tcp.port = htons(port);
|
||||
if (nf_ct_expect_related(exp) == 0)
|
||||
ret = nf_ct_expect_related(exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ __nf_nat_proto_find(u_int8_t protonum)
|
|||
return rcu_dereference(nf_nat_protos[protonum]);
|
||||
}
|
||||
|
||||
const struct nf_nat_protocol *
|
||||
static const struct nf_nat_protocol *
|
||||
nf_nat_proto_find_get(u_int8_t protonum)
|
||||
{
|
||||
const struct nf_nat_protocol *p;
|
||||
|
|
@ -60,14 +60,12 @@ nf_nat_proto_find_get(u_int8_t protonum)
|
|||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_proto_find_get);
|
||||
|
||||
void
|
||||
static void
|
||||
nf_nat_proto_put(const struct nf_nat_protocol *p)
|
||||
{
|
||||
module_put(p->me);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_proto_put);
|
||||
|
||||
/* We keep an extra hash for each conntrack, for fast searching. */
|
||||
static inline unsigned int
|
||||
|
|
@ -262,11 +260,17 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
|
|||
proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
|
||||
|
||||
/* Only bother mapping if it's not already in range and unique */
|
||||
if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM) &&
|
||||
(!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
|
||||
proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
|
||||
!nf_nat_used_tuple(tuple, ct))
|
||||
goto out;
|
||||
if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
|
||||
if (range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
|
||||
if (proto->in_range(tuple, maniptype, &range->min,
|
||||
&range->max) &&
|
||||
(range->min.all == range->max.all ||
|
||||
!nf_nat_used_tuple(tuple, ct)))
|
||||
goto out;
|
||||
} else if (!nf_nat_used_tuple(tuple, ct)) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Last change: get protocol to try to obtain unique tuple. */
|
||||
proto->unique_tuple(tuple, range, maniptype, ct);
|
||||
|
|
@ -458,6 +462,18 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (manip == IP_NAT_MANIP_SRC)
|
||||
statusbit = IPS_SRC_NAT;
|
||||
else
|
||||
statusbit = IPS_DST_NAT;
|
||||
|
||||
/* Invert if this is reply dir. */
|
||||
if (dir == IP_CT_DIR_REPLY)
|
||||
statusbit ^= IPS_NAT_MASK;
|
||||
|
||||
if (!(ct->status & statusbit))
|
||||
return 1;
|
||||
|
||||
pr_debug("icmp_reply_translation: translating error %p manip %u "
|
||||
"dir %s\n", skb, manip,
|
||||
dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
|
||||
|
|
@ -492,20 +508,9 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
|
|||
|
||||
/* Change outer to look the reply to an incoming packet
|
||||
* (proto 0 means don't invert per-proto part). */
|
||||
if (manip == IP_NAT_MANIP_SRC)
|
||||
statusbit = IPS_SRC_NAT;
|
||||
else
|
||||
statusbit = IPS_DST_NAT;
|
||||
|
||||
/* Invert if this is reply dir. */
|
||||
if (dir == IP_CT_DIR_REPLY)
|
||||
statusbit ^= IPS_NAT_MASK;
|
||||
|
||||
if (ct->status & statusbit) {
|
||||
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
|
||||
if (!manip_pkt(0, skb, 0, &target, manip))
|
||||
return 0;
|
||||
}
|
||||
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
|
||||
if (!manip_pkt(0, skb, 0, &target, manip))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,9 +79,16 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
|
|||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
|
||||
int ret;
|
||||
|
||||
exp->tuple.dst.u.tcp.port = htons(port);
|
||||
if (nf_ct_expect_related(exp) == 0)
|
||||
ret = nf_ct_expect_related(exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
|
|
|
|||
|
|
@ -222,13 +222,24 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
|
|||
/* Try to get a pair of ports. */
|
||||
for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
|
||||
nated_port != 0; nated_port += 2) {
|
||||
int ret;
|
||||
|
||||
rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
|
||||
if (nf_ct_expect_related(rtp_exp) == 0) {
|
||||
ret = nf_ct_expect_related(rtp_exp);
|
||||
if (ret == 0) {
|
||||
rtcp_exp->tuple.dst.u.udp.port =
|
||||
htons(nated_port + 1);
|
||||
if (nf_ct_expect_related(rtcp_exp) == 0)
|
||||
ret = nf_ct_expect_related(rtcp_exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
nf_ct_unexpect_related(rtp_exp);
|
||||
else if (ret != -EBUSY) {
|
||||
nf_ct_unexpect_related(rtp_exp);
|
||||
nated_port = 0;
|
||||
break;
|
||||
}
|
||||
} else if (ret != -EBUSY) {
|
||||
nated_port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,9 +295,16 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
|
|||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
int ret;
|
||||
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (nf_ct_expect_related(exp) == 0)
|
||||
ret = nf_ct_expect_related(exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
nated_port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
|
|
@ -334,9 +352,16 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
|
|||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
int ret;
|
||||
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (nf_ct_expect_related(exp) == 0)
|
||||
ret = nf_ct_expect_related(exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
nated_port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
|
|
@ -418,9 +443,16 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
|
|||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
int ret;
|
||||
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (nf_ct_expect_related(exp) == 0)
|
||||
ret = nf_ct_expect_related(exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
nated_port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
|
|
@ -500,9 +532,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
|
|||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (nated_port = ntohs(port); nated_port != 0; nated_port++) {
|
||||
int ret;
|
||||
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (nf_ct_expect_related(exp) == 0)
|
||||
ret = nf_ct_expect_related(exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
nated_port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
|
|
|
|||
|
|
@ -153,6 +153,35 @@ void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
|
||||
|
||||
static void nf_nat_csum(struct sk_buff *skb, struct iphdr *iph, void *data,
|
||||
int datalen, __sum16 *check, int oldlen)
|
||||
{
|
||||
struct rtable *rt = skb_rtable(skb);
|
||||
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||
if (!(rt->rt_flags & RTCF_LOCAL) &&
|
||||
skb->dev->features & NETIF_F_V4_CSUM) {
|
||||
skb->ip_summed = CHECKSUM_PARTIAL;
|
||||
skb->csum_start = skb_headroom(skb) +
|
||||
skb_network_offset(skb) +
|
||||
iph->ihl * 4;
|
||||
skb->csum_offset = (void *)check - data;
|
||||
*check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
|
||||
datalen, iph->protocol, 0);
|
||||
} else {
|
||||
*check = 0;
|
||||
*check = csum_tcpudp_magic(iph->saddr, iph->daddr,
|
||||
datalen, iph->protocol,
|
||||
csum_partial(data, datalen,
|
||||
0));
|
||||
if (iph->protocol == IPPROTO_UDP && !*check)
|
||||
*check = CSUM_MANGLED_0;
|
||||
}
|
||||
} else
|
||||
inet_proto_csum_replace2(check, skb,
|
||||
htons(oldlen), htons(datalen), 1);
|
||||
}
|
||||
|
||||
/* Generic function for mangling variable-length address changes inside
|
||||
* NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
|
||||
* command in FTP).
|
||||
|
|
@ -169,7 +198,6 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
|
|||
const char *rep_buffer,
|
||||
unsigned int rep_len, bool adjust)
|
||||
{
|
||||
struct rtable *rt = skb_rtable(skb);
|
||||
struct iphdr *iph;
|
||||
struct tcphdr *tcph;
|
||||
int oldlen, datalen;
|
||||
|
|
@ -192,26 +220,7 @@ int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
|
|||
match_offset, match_len, rep_buffer, rep_len);
|
||||
|
||||
datalen = skb->len - iph->ihl*4;
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||
if (!(rt->rt_flags & RTCF_LOCAL) &&
|
||||
skb->dev->features & NETIF_F_V4_CSUM) {
|
||||
skb->ip_summed = CHECKSUM_PARTIAL;
|
||||
skb->csum_start = skb_headroom(skb) +
|
||||
skb_network_offset(skb) +
|
||||
iph->ihl * 4;
|
||||
skb->csum_offset = offsetof(struct tcphdr, check);
|
||||
tcph->check = ~tcp_v4_check(datalen,
|
||||
iph->saddr, iph->daddr, 0);
|
||||
} else {
|
||||
tcph->check = 0;
|
||||
tcph->check = tcp_v4_check(datalen,
|
||||
iph->saddr, iph->daddr,
|
||||
csum_partial(tcph,
|
||||
datalen, 0));
|
||||
}
|
||||
} else
|
||||
inet_proto_csum_replace2(&tcph->check, skb,
|
||||
htons(oldlen), htons(datalen), 1);
|
||||
nf_nat_csum(skb, iph, tcph, datalen, &tcph->check, oldlen);
|
||||
|
||||
if (adjust && rep_len != match_len)
|
||||
nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
|
||||
|
|
@ -240,7 +249,6 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
|
|||
const char *rep_buffer,
|
||||
unsigned int rep_len)
|
||||
{
|
||||
struct rtable *rt = skb_rtable(skb);
|
||||
struct iphdr *iph;
|
||||
struct udphdr *udph;
|
||||
int datalen, oldlen;
|
||||
|
|
@ -274,29 +282,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
|
|||
if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
|
||||
return 1;
|
||||
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||
if (!(rt->rt_flags & RTCF_LOCAL) &&
|
||||
skb->dev->features & NETIF_F_V4_CSUM) {
|
||||
skb->ip_summed = CHECKSUM_PARTIAL;
|
||||
skb->csum_start = skb_headroom(skb) +
|
||||
skb_network_offset(skb) +
|
||||
iph->ihl * 4;
|
||||
skb->csum_offset = offsetof(struct udphdr, check);
|
||||
udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
|
||||
datalen, IPPROTO_UDP,
|
||||
0);
|
||||
} else {
|
||||
udph->check = 0;
|
||||
udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
|
||||
datalen, IPPROTO_UDP,
|
||||
csum_partial(udph,
|
||||
datalen, 0));
|
||||
if (!udph->check)
|
||||
udph->check = CSUM_MANGLED_0;
|
||||
}
|
||||
} else
|
||||
inet_proto_csum_replace2(&udph->check, skb,
|
||||
htons(oldlen), htons(datalen), 1);
|
||||
nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,9 +45,16 @@ static unsigned int help(struct sk_buff *skb,
|
|||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
|
||||
int ret;
|
||||
|
||||
exp->tuple.dst.u.tcp.port = htons(port);
|
||||
if (nf_ct_expect_related(exp) == 0)
|
||||
ret = nf_ct_expect_related(exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
|
|
|
|||
|
|
@ -106,16 +106,15 @@ alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
|
|||
{
|
||||
/* Force range to this IP; let proto decide mapping for
|
||||
per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
|
||||
Use reply in case it's already been mangled (eg local packet).
|
||||
*/
|
||||
__be32 ip
|
||||
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
|
||||
? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip
|
||||
: ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
|
||||
struct nf_nat_range range
|
||||
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } };
|
||||
struct nf_nat_range range;
|
||||
|
||||
range.flags = 0;
|
||||
pr_debug("Allocating NULL binding for %p (%pI4)\n", ct,
|
||||
HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ?
|
||||
&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip :
|
||||
&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
|
||||
|
||||
pr_debug("Allocating NULL binding for %p (%pI4)\n", ct, &ip);
|
||||
return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,9 +307,16 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
|
|||
exp->expectfn = ip_nat_sip_expected;
|
||||
|
||||
for (; port != 0; port++) {
|
||||
int ret;
|
||||
|
||||
exp->tuple.dst.u.udp.port = htons(port);
|
||||
if (nf_ct_expect_related(exp) == 0)
|
||||
ret = nf_ct_expect_related(exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
|
|
@ -480,13 +487,25 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
|
|||
/* Try to get same pair of ports: if not, try to change them. */
|
||||
for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
|
||||
port != 0; port += 2) {
|
||||
int ret;
|
||||
|
||||
rtp_exp->tuple.dst.u.udp.port = htons(port);
|
||||
if (nf_ct_expect_related(rtp_exp) != 0)
|
||||
ret = nf_ct_expect_related(rtp_exp);
|
||||
if (ret == -EBUSY)
|
||||
continue;
|
||||
rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
|
||||
if (nf_ct_expect_related(rtcp_exp) == 0)
|
||||
else if (ret < 0) {
|
||||
port = 0;
|
||||
break;
|
||||
nf_ct_unexpect_related(rtp_exp);
|
||||
}
|
||||
rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
|
||||
ret = nf_ct_expect_related(rtcp_exp);
|
||||
if (ret == 0)
|
||||
break;
|
||||
else if (ret != -EBUSY) {
|
||||
nf_ct_unexpect_related(rtp_exp);
|
||||
port = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <net/protocol.h>
|
||||
|
||||
const struct net_protocol *inet_protos[MAX_INET_PROTOS] ____cacheline_aligned_in_smp;
|
||||
static DEFINE_SPINLOCK(inet_proto_lock);
|
||||
const struct net_protocol *inet_protos[MAX_INET_PROTOS] __read_mostly;
|
||||
|
||||
/*
|
||||
* Add a protocol handler to the hash tables
|
||||
|
|
@ -37,20 +36,9 @@ static DEFINE_SPINLOCK(inet_proto_lock);
|
|||
|
||||
int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
|
||||
{
|
||||
int hash, ret;
|
||||
int hash = protocol & (MAX_INET_PROTOS - 1);
|
||||
|
||||
hash = protocol & (MAX_INET_PROTOS - 1);
|
||||
|
||||
spin_lock_bh(&inet_proto_lock);
|
||||
if (inet_protos[hash]) {
|
||||
ret = -1;
|
||||
} else {
|
||||
inet_protos[hash] = prot;
|
||||
ret = 0;
|
||||
}
|
||||
spin_unlock_bh(&inet_proto_lock);
|
||||
|
||||
return ret;
|
||||
return !cmpxchg(&inet_protos[hash], NULL, prot) ? 0 : -1;
|
||||
}
|
||||
EXPORT_SYMBOL(inet_add_protocol);
|
||||
|
||||
|
|
@ -60,18 +48,9 @@ EXPORT_SYMBOL(inet_add_protocol);
|
|||
|
||||
int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol)
|
||||
{
|
||||
int hash, ret;
|
||||
int ret, hash = protocol & (MAX_INET_PROTOS - 1);
|
||||
|
||||
hash = protocol & (MAX_INET_PROTOS - 1);
|
||||
|
||||
spin_lock_bh(&inet_proto_lock);
|
||||
if (inet_protos[hash] == prot) {
|
||||
inet_protos[hash] = NULL;
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
spin_unlock_bh(&inet_proto_lock);
|
||||
ret = (cmpxchg(&inet_protos[hash], prot, NULL) == prot) ? 0 : -1;
|
||||
|
||||
synchronize_net();
|
||||
|
||||
|
|
|
|||
|
|
@ -505,7 +505,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||
|
||||
ipc.addr = inet->inet_saddr;
|
||||
ipc.opt = NULL;
|
||||
ipc.shtx.flags = 0;
|
||||
ipc.tx_flags = 0;
|
||||
ipc.oif = sk->sk_bound_dev_if;
|
||||
|
||||
if (msg->msg_controllen) {
|
||||
|
|
|
|||
190
net/ipv4/route.c
190
net/ipv4/route.c
|
|
@ -159,7 +159,6 @@ static struct dst_ops ipv4_dst_ops = {
|
|||
.link_failure = ipv4_link_failure,
|
||||
.update_pmtu = ip_rt_update_pmtu,
|
||||
.local_out = __ip_local_out,
|
||||
.entries = ATOMIC_INIT(0),
|
||||
};
|
||||
|
||||
#define ECN_OR_COST(class) TC_PRIO_##class
|
||||
|
|
@ -466,7 +465,7 @@ static int rt_cpu_seq_show(struct seq_file *seq, void *v)
|
|||
|
||||
seq_printf(seq,"%08x %08x %08x %08x %08x %08x %08x %08x "
|
||||
" %08x %08x %08x %08x %08x %08x %08x %08x %08x \n",
|
||||
atomic_read(&ipv4_dst_ops.entries),
|
||||
dst_entries_get_slow(&ipv4_dst_ops),
|
||||
st->in_hit,
|
||||
st->in_slow_tot,
|
||||
st->in_slow_mc,
|
||||
|
|
@ -945,6 +944,7 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
|||
struct rtable *rth, **rthp;
|
||||
unsigned long now = jiffies;
|
||||
int goal;
|
||||
int entries = dst_entries_get_fast(&ipv4_dst_ops);
|
||||
|
||||
/*
|
||||
* Garbage collection is pretty expensive,
|
||||
|
|
@ -954,28 +954,28 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
|||
RT_CACHE_STAT_INC(gc_total);
|
||||
|
||||
if (now - last_gc < ip_rt_gc_min_interval &&
|
||||
atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size) {
|
||||
entries < ip_rt_max_size) {
|
||||
RT_CACHE_STAT_INC(gc_ignored);
|
||||
goto out;
|
||||
}
|
||||
|
||||
entries = dst_entries_get_slow(&ipv4_dst_ops);
|
||||
/* Calculate number of entries, which we want to expire now. */
|
||||
goal = atomic_read(&ipv4_dst_ops.entries) -
|
||||
(ip_rt_gc_elasticity << rt_hash_log);
|
||||
goal = entries - (ip_rt_gc_elasticity << rt_hash_log);
|
||||
if (goal <= 0) {
|
||||
if (equilibrium < ipv4_dst_ops.gc_thresh)
|
||||
equilibrium = ipv4_dst_ops.gc_thresh;
|
||||
goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
|
||||
goal = entries - equilibrium;
|
||||
if (goal > 0) {
|
||||
equilibrium += min_t(unsigned int, goal >> 1, rt_hash_mask + 1);
|
||||
goal = atomic_read(&ipv4_dst_ops.entries) - equilibrium;
|
||||
goal = entries - equilibrium;
|
||||
}
|
||||
} else {
|
||||
/* We are in dangerous area. Try to reduce cache really
|
||||
* aggressively.
|
||||
*/
|
||||
goal = max_t(unsigned int, goal >> 1, rt_hash_mask + 1);
|
||||
equilibrium = atomic_read(&ipv4_dst_ops.entries) - goal;
|
||||
equilibrium = entries - goal;
|
||||
}
|
||||
|
||||
if (now - last_gc >= ip_rt_gc_min_interval)
|
||||
|
|
@ -1032,14 +1032,16 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
|||
expire >>= 1;
|
||||
#if RT_CACHE_DEBUG >= 2
|
||||
printk(KERN_DEBUG "expire>> %u %d %d %d\n", expire,
|
||||
atomic_read(&ipv4_dst_ops.entries), goal, i);
|
||||
dst_entries_get_fast(&ipv4_dst_ops), goal, i);
|
||||
#endif
|
||||
|
||||
if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
|
||||
if (dst_entries_get_fast(&ipv4_dst_ops) < ip_rt_max_size)
|
||||
goto out;
|
||||
} while (!in_softirq() && time_before_eq(jiffies, now));
|
||||
|
||||
if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
|
||||
if (dst_entries_get_fast(&ipv4_dst_ops) < ip_rt_max_size)
|
||||
goto out;
|
||||
if (dst_entries_get_slow(&ipv4_dst_ops) < ip_rt_max_size)
|
||||
goto out;
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "dst cache overflow\n");
|
||||
|
|
@ -1049,11 +1051,12 @@ static int rt_garbage_collect(struct dst_ops *ops)
|
|||
work_done:
|
||||
expire += ip_rt_gc_min_interval;
|
||||
if (expire > ip_rt_gc_timeout ||
|
||||
atomic_read(&ipv4_dst_ops.entries) < ipv4_dst_ops.gc_thresh)
|
||||
dst_entries_get_fast(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh ||
|
||||
dst_entries_get_slow(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh)
|
||||
expire = ip_rt_gc_timeout;
|
||||
#if RT_CACHE_DEBUG >= 2
|
||||
printk(KERN_DEBUG "expire++ %u %d %d %d\n", expire,
|
||||
atomic_read(&ipv4_dst_ops.entries), goal, rover);
|
||||
dst_entries_get_fast(&ipv4_dst_ops), goal, rover);
|
||||
#endif
|
||||
out: return 0;
|
||||
}
|
||||
|
|
@ -1102,23 +1105,23 @@ restart:
|
|||
* Note that we do rt_free on this new route entry, so that
|
||||
* once its refcount hits zero, we are still able to reap it
|
||||
* (Thanks Alexey)
|
||||
* Note also the rt_free uses call_rcu. We don't actually
|
||||
* need rcu protection here, this is just our path to get
|
||||
* on the route gc list.
|
||||
* Note: To avoid expensive rcu stuff for this uncached dst,
|
||||
* we set DST_NOCACHE so that dst_release() can free dst without
|
||||
* waiting a grace period.
|
||||
*/
|
||||
|
||||
rt->dst.flags |= DST_NOCACHE;
|
||||
if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
|
||||
int err = arp_bind_neighbour(&rt->dst);
|
||||
if (err) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING
|
||||
"Neighbour table failure & not caching routes.\n");
|
||||
rt_drop(rt);
|
||||
ip_rt_put(rt);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
rt_free(rt);
|
||||
goto skip_hashing;
|
||||
}
|
||||
|
||||
|
|
@ -1268,18 +1271,11 @@ skip_hashing:
|
|||
|
||||
void rt_bind_peer(struct rtable *rt, int create)
|
||||
{
|
||||
static DEFINE_SPINLOCK(rt_peer_lock);
|
||||
struct inet_peer *peer;
|
||||
|
||||
peer = inet_getpeer(rt->rt_dst, create);
|
||||
|
||||
spin_lock_bh(&rt_peer_lock);
|
||||
if (rt->peer == NULL) {
|
||||
rt->peer = peer;
|
||||
peer = NULL;
|
||||
}
|
||||
spin_unlock_bh(&rt_peer_lock);
|
||||
if (peer)
|
||||
if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
|
||||
inet_putpeer(peer);
|
||||
}
|
||||
|
||||
|
|
@ -1779,12 +1775,15 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
|
|||
|
||||
if (rt->fl.iif == 0)
|
||||
src = rt->rt_src;
|
||||
else if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0) {
|
||||
src = FIB_RES_PREFSRC(res);
|
||||
fib_res_put(&res);
|
||||
} else
|
||||
src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
|
||||
else {
|
||||
rcu_read_lock();
|
||||
if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0)
|
||||
src = FIB_RES_PREFSRC(res);
|
||||
else
|
||||
src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
|
||||
RT_SCOPE_UNIVERSE);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
memcpy(addr, &src, 4);
|
||||
}
|
||||
|
||||
|
|
@ -2087,6 +2086,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
|
|||
* Such approach solves two big problems:
|
||||
* 1. Not simplex devices are handled properly.
|
||||
* 2. IP spoofing attempts are filtered with 100% of guarantee.
|
||||
* called with rcu_read_lock()
|
||||
*/
|
||||
|
||||
static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
||||
|
|
@ -2108,7 +2108,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
unsigned hash;
|
||||
__be32 spec_dst;
|
||||
int err = -EINVAL;
|
||||
int free_res = 0;
|
||||
struct net * net = dev_net(dev);
|
||||
|
||||
/* IP on this device is disabled. */
|
||||
|
|
@ -2124,7 +2123,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
ipv4_is_loopback(saddr))
|
||||
goto martian_source;
|
||||
|
||||
if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0))
|
||||
if (ipv4_is_lbcast(daddr) || (saddr == 0 && daddr == 0))
|
||||
goto brd_input;
|
||||
|
||||
/* Accept zero addresses only to limited broadcast;
|
||||
|
|
@ -2133,19 +2132,18 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
if (ipv4_is_zeronet(saddr))
|
||||
goto martian_source;
|
||||
|
||||
if (ipv4_is_lbcast(daddr) || ipv4_is_zeronet(daddr) ||
|
||||
ipv4_is_loopback(daddr))
|
||||
if (ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr))
|
||||
goto martian_destination;
|
||||
|
||||
/*
|
||||
* Now we are ready to route packet.
|
||||
*/
|
||||
if ((err = fib_lookup(net, &fl, &res)) != 0) {
|
||||
err = fib_lookup(net, &fl, &res);
|
||||
if (err != 0) {
|
||||
if (!IN_DEV_FORWARD(in_dev))
|
||||
goto e_hostunreach;
|
||||
goto no_route;
|
||||
}
|
||||
free_res = 1;
|
||||
|
||||
RT_CACHE_STAT_INC(in_slow_tot);
|
||||
|
||||
|
|
@ -2154,8 +2152,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
|
||||
if (res.type == RTN_LOCAL) {
|
||||
err = fib_validate_source(saddr, daddr, tos,
|
||||
net->loopback_dev->ifindex,
|
||||
dev, &spec_dst, &itag, skb->mark);
|
||||
net->loopback_dev->ifindex,
|
||||
dev, &spec_dst, &itag, skb->mark);
|
||||
if (err < 0)
|
||||
goto martian_source_keep_err;
|
||||
if (err)
|
||||
|
|
@ -2170,9 +2168,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
|||
goto martian_destination;
|
||||
|
||||
err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
|
||||
done:
|
||||
if (free_res)
|
||||
fib_res_put(&res);
|
||||
out: return err;
|
||||
|
||||
brd_input:
|
||||
|
|
@ -2232,7 +2227,7 @@ local_input:
|
|||
rth->rt_type = res.type;
|
||||
hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
|
||||
err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);
|
||||
goto done;
|
||||
goto out;
|
||||
|
||||
no_route:
|
||||
RT_CACHE_STAT_INC(in_no_route);
|
||||
|
|
@ -2255,21 +2250,21 @@ martian_destination:
|
|||
|
||||
e_hostunreach:
|
||||
err = -EHOSTUNREACH;
|
||||
goto done;
|
||||
goto out;
|
||||
|
||||
e_inval:
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
goto out;
|
||||
|
||||
e_nobufs:
|
||||
err = -ENOBUFS;
|
||||
goto done;
|
||||
goto out;
|
||||
|
||||
martian_source:
|
||||
err = -EINVAL;
|
||||
martian_source_keep_err:
|
||||
ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
|
||||
goto done;
|
||||
goto out;
|
||||
}
|
||||
|
||||
int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
||||
|
|
@ -2355,6 +2350,7 @@ skip_cache:
|
|||
}
|
||||
EXPORT_SYMBOL(ip_route_input_common);
|
||||
|
||||
/* called with rcu_read_lock() */
|
||||
static int __mkroute_output(struct rtable **result,
|
||||
struct fib_result *res,
|
||||
const struct flowi *fl,
|
||||
|
|
@ -2365,53 +2361,47 @@ static int __mkroute_output(struct rtable **result,
|
|||
struct rtable *rth;
|
||||
struct in_device *in_dev;
|
||||
u32 tos = RT_FL_TOS(oldflp);
|
||||
int err = 0;
|
||||
|
||||
if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
|
||||
if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags & IFF_LOOPBACK))
|
||||
return -EINVAL;
|
||||
|
||||
if (fl->fl4_dst == htonl(0xFFFFFFFF))
|
||||
if (ipv4_is_lbcast(fl->fl4_dst))
|
||||
res->type = RTN_BROADCAST;
|
||||
else if (ipv4_is_multicast(fl->fl4_dst))
|
||||
res->type = RTN_MULTICAST;
|
||||
else if (ipv4_is_lbcast(fl->fl4_dst) || ipv4_is_zeronet(fl->fl4_dst))
|
||||
else if (ipv4_is_zeronet(fl->fl4_dst))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev_out->flags & IFF_LOOPBACK)
|
||||
flags |= RTCF_LOCAL;
|
||||
|
||||
/* get work reference to inet device */
|
||||
in_dev = in_dev_get(dev_out);
|
||||
in_dev = __in_dev_get_rcu(dev_out);
|
||||
if (!in_dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (res->type == RTN_BROADCAST) {
|
||||
flags |= RTCF_BROADCAST | RTCF_LOCAL;
|
||||
if (res->fi) {
|
||||
fib_info_put(res->fi);
|
||||
res->fi = NULL;
|
||||
}
|
||||
res->fi = NULL;
|
||||
} else if (res->type == RTN_MULTICAST) {
|
||||
flags |= RTCF_MULTICAST|RTCF_LOCAL;
|
||||
flags |= RTCF_MULTICAST | RTCF_LOCAL;
|
||||
if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src,
|
||||
oldflp->proto))
|
||||
flags &= ~RTCF_LOCAL;
|
||||
/* If multicast route do not exist use
|
||||
default one, but do not gateway in this case.
|
||||
Yes, it is hack.
|
||||
* default one, but do not gateway in this case.
|
||||
* Yes, it is hack.
|
||||
*/
|
||||
if (res->fi && res->prefixlen < 4) {
|
||||
fib_info_put(res->fi);
|
||||
if (res->fi && res->prefixlen < 4)
|
||||
res->fi = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rth = dst_alloc(&ipv4_dst_ops);
|
||||
if (!rth) {
|
||||
err = -ENOBUFS;
|
||||
goto cleanup;
|
||||
}
|
||||
if (!rth)
|
||||
return -ENOBUFS;
|
||||
|
||||
in_dev_hold(in_dev);
|
||||
rth->idev = in_dev;
|
||||
|
||||
atomic_set(&rth->dst.__refcnt, 1);
|
||||
rth->dst.flags= DST_HOST;
|
||||
|
|
@ -2432,7 +2422,6 @@ static int __mkroute_output(struct rtable **result,
|
|||
cache entry */
|
||||
rth->dst.dev = dev_out;
|
||||
dev_hold(dev_out);
|
||||
rth->idev = in_dev_get(dev_out);
|
||||
rth->rt_gateway = fl->fl4_dst;
|
||||
rth->rt_spec_dst= fl->fl4_src;
|
||||
|
||||
|
|
@ -2467,15 +2456,11 @@ static int __mkroute_output(struct rtable **result,
|
|||
rt_set_nexthop(rth, res, 0);
|
||||
|
||||
rth->rt_flags = flags;
|
||||
|
||||
*result = rth;
|
||||
cleanup:
|
||||
/* release work reference to inet device */
|
||||
in_dev_put(in_dev);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called with rcu_read_lock() */
|
||||
static int ip_mkroute_output(struct rtable **rp,
|
||||
struct fib_result *res,
|
||||
const struct flowi *fl,
|
||||
|
|
@ -2497,6 +2482,7 @@ static int ip_mkroute_output(struct rtable **rp,
|
|||
|
||||
/*
|
||||
* Major route resolver routine.
|
||||
* called with rcu_read_lock();
|
||||
*/
|
||||
|
||||
static int ip_route_output_slow(struct net *net, struct rtable **rp,
|
||||
|
|
@ -2515,9 +2501,8 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
|
|||
.iif = net->loopback_dev->ifindex,
|
||||
.oif = oldflp->oif };
|
||||
struct fib_result res;
|
||||
unsigned flags = 0;
|
||||
unsigned int flags = 0;
|
||||
struct net_device *dev_out = NULL;
|
||||
int free_res = 0;
|
||||
int err;
|
||||
|
||||
|
||||
|
|
@ -2543,9 +2528,9 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
|
|||
|
||||
if (oldflp->oif == 0 &&
|
||||
(ipv4_is_multicast(oldflp->fl4_dst) ||
|
||||
oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
|
||||
ipv4_is_lbcast(oldflp->fl4_dst))) {
|
||||
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
|
||||
dev_out = ip_dev_find(net, oldflp->fl4_src);
|
||||
dev_out = __ip_dev_find(net, oldflp->fl4_src, false);
|
||||
if (dev_out == NULL)
|
||||
goto out;
|
||||
|
||||
|
|
@ -2570,29 +2555,24 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
|
|||
|
||||
if (!(oldflp->flags & FLOWI_FLAG_ANYSRC)) {
|
||||
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
|
||||
dev_out = ip_dev_find(net, oldflp->fl4_src);
|
||||
if (dev_out == NULL)
|
||||
if (!__ip_dev_find(net, oldflp->fl4_src, false))
|
||||
goto out;
|
||||
dev_put(dev_out);
|
||||
dev_out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (oldflp->oif) {
|
||||
dev_out = dev_get_by_index(net, oldflp->oif);
|
||||
dev_out = dev_get_by_index_rcu(net, oldflp->oif);
|
||||
err = -ENODEV;
|
||||
if (dev_out == NULL)
|
||||
goto out;
|
||||
|
||||
/* RACE: Check return value of inet_select_addr instead. */
|
||||
if (__in_dev_get_rtnl(dev_out) == NULL) {
|
||||
dev_put(dev_out);
|
||||
if (rcu_dereference(dev_out->ip_ptr) == NULL)
|
||||
goto out; /* Wrong error code */
|
||||
}
|
||||
|
||||
if (ipv4_is_local_multicast(oldflp->fl4_dst) ||
|
||||
oldflp->fl4_dst == htonl(0xFFFFFFFF)) {
|
||||
ipv4_is_lbcast(oldflp->fl4_dst)) {
|
||||
if (!fl.fl4_src)
|
||||
fl.fl4_src = inet_select_addr(dev_out, 0,
|
||||
RT_SCOPE_LINK);
|
||||
|
|
@ -2612,10 +2592,7 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
|
|||
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 = net->loopback_dev;
|
||||
dev_hold(dev_out);
|
||||
fl.oif = net->loopback_dev->ifindex;
|
||||
res.type = RTN_LOCAL;
|
||||
flags |= RTCF_LOCAL;
|
||||
|
|
@ -2649,23 +2626,15 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
|
|||
res.type = RTN_UNICAST;
|
||||
goto make_route;
|
||||
}
|
||||
if (dev_out)
|
||||
dev_put(dev_out);
|
||||
err = -ENETUNREACH;
|
||||
goto out;
|
||||
}
|
||||
free_res = 1;
|
||||
|
||||
if (res.type == RTN_LOCAL) {
|
||||
if (!fl.fl4_src)
|
||||
fl.fl4_src = fl.fl4_dst;
|
||||
if (dev_out)
|
||||
dev_put(dev_out);
|
||||
dev_out = net->loopback_dev;
|
||||
dev_hold(dev_out);
|
||||
fl.oif = dev_out->ifindex;
|
||||
if (res.fi)
|
||||
fib_info_put(res.fi);
|
||||
res.fi = NULL;
|
||||
flags |= RTCF_LOCAL;
|
||||
goto make_route;
|
||||
|
|
@ -2682,28 +2651,21 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
|
|||
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);
|
||||
fl.oif = dev_out->ifindex;
|
||||
|
||||
|
||||
make_route:
|
||||
err = ip_mkroute_output(rp, &res, &fl, oldflp, dev_out, flags);
|
||||
|
||||
|
||||
if (free_res)
|
||||
fib_res_put(&res);
|
||||
if (dev_out)
|
||||
dev_put(dev_out);
|
||||
out: return err;
|
||||
}
|
||||
|
||||
int __ip_route_output_key(struct net *net, struct rtable **rp,
|
||||
const struct flowi *flp)
|
||||
{
|
||||
unsigned hash;
|
||||
unsigned int hash;
|
||||
int res;
|
||||
struct rtable *rth;
|
||||
|
||||
if (!rt_caching(net))
|
||||
|
|
@ -2734,7 +2696,10 @@ int __ip_route_output_key(struct net *net, struct rtable **rp,
|
|||
rcu_read_unlock_bh();
|
||||
|
||||
slow_output:
|
||||
return ip_route_output_slow(net, rp, flp);
|
||||
rcu_read_lock();
|
||||
res = ip_route_output_slow(net, rp, flp);
|
||||
rcu_read_unlock();
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__ip_route_output_key);
|
||||
|
||||
|
|
@ -2753,7 +2718,6 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
|
|||
.destroy = ipv4_dst_destroy,
|
||||
.check = ipv4_blackhole_dst_check,
|
||||
.update_pmtu = ipv4_rt_blackhole_update_pmtu,
|
||||
.entries = ATOMIC_INIT(0),
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -2798,7 +2762,7 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
|
|||
|
||||
dst_release(&(*rp)->dst);
|
||||
*rp = rt;
|
||||
return (rt ? 0 : -ENOMEM);
|
||||
return rt ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
|
||||
|
|
@ -3323,6 +3287,12 @@ int __init ip_rt_init(void)
|
|||
|
||||
ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep;
|
||||
|
||||
if (dst_entries_init(&ipv4_dst_ops) < 0)
|
||||
panic("IP: failed to allocate ipv4_dst_ops counter\n");
|
||||
|
||||
if (dst_entries_init(&ipv4_dst_blackhole_ops) < 0)
|
||||
panic("IP: failed to allocate ipv4_dst_blackhole_ops counter\n");
|
||||
|
||||
rt_hash_table = (struct rt_hash_bucket *)
|
||||
alloc_large_system_hash("IP route cache",
|
||||
sizeof(struct rt_hash_bucket),
|
||||
|
|
|
|||
|
|
@ -2392,7 +2392,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
|
|||
err = tp->af_specific->md5_parse(sk, optval, optlen);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TCP_USER_TIMEOUT:
|
||||
/* Cap the max timeout in ms TCP will retry/retrans
|
||||
* before giving up and aborting (ETIMEDOUT) a connection.
|
||||
*/
|
||||
icsk->icsk_user_timeout = msecs_to_jiffies(val);
|
||||
break;
|
||||
default:
|
||||
err = -ENOPROTOOPT;
|
||||
break;
|
||||
|
|
@ -2611,6 +2616,10 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
|
|||
case TCP_THIN_DUPACK:
|
||||
val = tp->thin_dupack;
|
||||
break;
|
||||
|
||||
case TCP_USER_TIMEOUT:
|
||||
val = jiffies_to_msecs(icsk->icsk_user_timeout);
|
||||
break;
|
||||
default:
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ static void tcp_incr_quickack(struct sock *sk)
|
|||
icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS);
|
||||
}
|
||||
|
||||
void tcp_enter_quickack_mode(struct sock *sk)
|
||||
static void tcp_enter_quickack_mode(struct sock *sk)
|
||||
{
|
||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||
tcp_incr_quickack(sk);
|
||||
|
|
@ -805,25 +805,12 @@ void tcp_update_metrics(struct sock *sk)
|
|||
}
|
||||
}
|
||||
|
||||
/* Numbers are taken from RFC3390.
|
||||
*
|
||||
* John Heffner states:
|
||||
*
|
||||
* The RFC specifies a window of no more than 4380 bytes
|
||||
* unless 2*MSS > 4380. Reading the pseudocode in the RFC
|
||||
* is a bit misleading because they use a clamp at 4380 bytes
|
||||
* rather than use a multiplier in the relevant range.
|
||||
*/
|
||||
__u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst)
|
||||
{
|
||||
__u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
|
||||
|
||||
if (!cwnd) {
|
||||
if (tp->mss_cache > 1460)
|
||||
cwnd = 2;
|
||||
else
|
||||
cwnd = (tp->mss_cache > 1095) ? 3 : 4;
|
||||
}
|
||||
if (!cwnd)
|
||||
cwnd = rfc3390_bytes_to_packets(tp->mss_cache);
|
||||
return min_t(__u32, cwnd, tp->snd_cwnd_clamp);
|
||||
}
|
||||
|
||||
|
|
@ -2314,7 +2301,7 @@ static inline int tcp_dupack_heuristics(struct tcp_sock *tp)
|
|||
|
||||
static inline int tcp_skb_timedout(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
return (tcp_time_stamp - TCP_SKB_CB(skb)->when > inet_csk(sk)->icsk_rto);
|
||||
return tcp_time_stamp - TCP_SKB_CB(skb)->when > inet_csk(sk)->icsk_rto;
|
||||
}
|
||||
|
||||
static inline int tcp_head_timedout(struct sock *sk)
|
||||
|
|
@ -2508,7 +2495,7 @@ static void tcp_timeout_skbs(struct sock *sk)
|
|||
/* Mark head of queue up as lost. With RFC3517 SACK, the packets is
|
||||
* is against sacked "cnt", otherwise it's against facked "cnt"
|
||||
*/
|
||||
static void tcp_mark_head_lost(struct sock *sk, int packets)
|
||||
static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head)
|
||||
{
|
||||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct sk_buff *skb;
|
||||
|
|
@ -2516,13 +2503,13 @@ static void tcp_mark_head_lost(struct sock *sk, int packets)
|
|||
int err;
|
||||
unsigned int mss;
|
||||
|
||||
if (packets == 0)
|
||||
return;
|
||||
|
||||
WARN_ON(packets > tp->packets_out);
|
||||
if (tp->lost_skb_hint) {
|
||||
skb = tp->lost_skb_hint;
|
||||
cnt = tp->lost_cnt_hint;
|
||||
/* Head already handled? */
|
||||
if (mark_head && skb != tcp_write_queue_head(sk))
|
||||
return;
|
||||
} else {
|
||||
skb = tcp_write_queue_head(sk);
|
||||
cnt = 0;
|
||||
|
|
@ -2557,6 +2544,9 @@ static void tcp_mark_head_lost(struct sock *sk, int packets)
|
|||
}
|
||||
|
||||
tcp_skb_mark_lost(tp, skb);
|
||||
|
||||
if (mark_head)
|
||||
break;
|
||||
}
|
||||
tcp_verify_left_out(tp);
|
||||
}
|
||||
|
|
@ -2568,17 +2558,18 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
|
|||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
|
||||
if (tcp_is_reno(tp)) {
|
||||
tcp_mark_head_lost(sk, 1);
|
||||
tcp_mark_head_lost(sk, 1, 1);
|
||||
} else if (tcp_is_fack(tp)) {
|
||||
int lost = tp->fackets_out - tp->reordering;
|
||||
if (lost <= 0)
|
||||
lost = 1;
|
||||
tcp_mark_head_lost(sk, lost);
|
||||
tcp_mark_head_lost(sk, lost, 0);
|
||||
} else {
|
||||
int sacked_upto = tp->sacked_out - tp->reordering;
|
||||
if (sacked_upto < fast_rexmit)
|
||||
sacked_upto = fast_rexmit;
|
||||
tcp_mark_head_lost(sk, sacked_upto);
|
||||
if (sacked_upto >= 0)
|
||||
tcp_mark_head_lost(sk, sacked_upto, 0);
|
||||
else if (fast_rexmit)
|
||||
tcp_mark_head_lost(sk, 1, 1);
|
||||
}
|
||||
|
||||
tcp_timeout_skbs(sk);
|
||||
|
|
@ -2887,7 +2878,7 @@ static void tcp_mtup_probe_success(struct sock *sk)
|
|||
icsk->icsk_mtup.probe_size;
|
||||
tp->snd_cwnd_cnt = 0;
|
||||
tp->snd_cwnd_stamp = tcp_time_stamp;
|
||||
tp->rcv_ssthresh = tcp_current_ssthresh(sk);
|
||||
tp->snd_ssthresh = tcp_current_ssthresh(sk);
|
||||
|
||||
icsk->icsk_mtup.search_low = icsk->icsk_mtup.probe_size;
|
||||
icsk->icsk_mtup.probe_size = 0;
|
||||
|
|
@ -2984,7 +2975,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
|
|||
before(tp->snd_una, tp->high_seq) &&
|
||||
icsk->icsk_ca_state != TCP_CA_Open &&
|
||||
tp->fackets_out > tp->reordering) {
|
||||
tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering);
|
||||
tcp_mark_head_lost(sk, tp->fackets_out - tp->reordering, 0);
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSS);
|
||||
}
|
||||
|
||||
|
|
@ -3412,8 +3403,8 @@ static void tcp_ack_probe(struct sock *sk)
|
|||
|
||||
static inline int tcp_ack_is_dubious(const struct sock *sk, const int flag)
|
||||
{
|
||||
return (!(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) ||
|
||||
inet_csk(sk)->icsk_ca_state != TCP_CA_Open);
|
||||
return !(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) ||
|
||||
inet_csk(sk)->icsk_ca_state != TCP_CA_Open;
|
||||
}
|
||||
|
||||
static inline int tcp_may_raise_cwnd(const struct sock *sk, const int flag)
|
||||
|
|
@ -3430,9 +3421,9 @@ static inline int tcp_may_update_window(const struct tcp_sock *tp,
|
|||
const u32 ack, const u32 ack_seq,
|
||||
const u32 nwin)
|
||||
{
|
||||
return (after(ack, tp->snd_una) ||
|
||||
return after(ack, tp->snd_una) ||
|
||||
after(ack_seq, tp->snd_wl1) ||
|
||||
(ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd));
|
||||
(ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd);
|
||||
}
|
||||
|
||||
/* Update our send window.
|
||||
|
|
|
|||
|
|
@ -1422,7 +1422,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
|
|||
|
||||
newsk = tcp_create_openreq_child(sk, req, skb);
|
||||
if (!newsk)
|
||||
goto exit;
|
||||
goto exit_nonewsk;
|
||||
|
||||
newsk->sk_gso_type = SKB_GSO_TCPV4;
|
||||
sk_setup_caps(newsk, dst);
|
||||
|
|
@ -1469,16 +1469,20 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (__inet_inherit_port(sk, newsk) < 0) {
|
||||
sock_put(newsk);
|
||||
goto exit;
|
||||
}
|
||||
__inet_hash_nolisten(newsk, NULL);
|
||||
__inet_inherit_port(sk, newsk);
|
||||
|
||||
return newsk;
|
||||
|
||||
exit_overflow:
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
|
||||
exit_nonewsk:
|
||||
dst_release(dst);
|
||||
exit:
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
|
||||
dst_release(dst);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
|
||||
|
|
@ -2571,7 +2575,6 @@ struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
|
|||
|
||||
return tcp_gro_receive(head, skb);
|
||||
}
|
||||
EXPORT_SYMBOL(tcp4_gro_receive);
|
||||
|
||||
int tcp4_gro_complete(struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -2584,7 +2587,6 @@ int tcp4_gro_complete(struct sk_buff *skb)
|
|||
|
||||
return tcp_gro_complete(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(tcp4_gro_complete);
|
||||
|
||||
struct proto tcp_prot = {
|
||||
.name = "TCP",
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
|
|||
return 1;
|
||||
if (after(end_seq, s_win) && before(seq, e_win))
|
||||
return 1;
|
||||
return (seq == e_win && seq == end_seq);
|
||||
return seq == e_win && seq == end_seq;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -224,16 +224,10 @@ void tcp_select_initial_window(int __space, __u32 mss,
|
|||
}
|
||||
}
|
||||
|
||||
/* Set initial window to value enough for senders,
|
||||
* following RFC2414. Senders, not following this RFC,
|
||||
* will be satisfied with 2.
|
||||
*/
|
||||
/* Set initial window to value enough for senders, following RFC5681. */
|
||||
if (mss > (1 << *rcv_wscale)) {
|
||||
int init_cwnd = 4;
|
||||
if (mss > 1460 * 3)
|
||||
init_cwnd = 2;
|
||||
else if (mss > 1460)
|
||||
init_cwnd = 3;
|
||||
int init_cwnd = rfc3390_bytes_to_packets(mss);
|
||||
|
||||
/* when initializing use the value from init_rcv_wnd
|
||||
* rather than the default from above
|
||||
*/
|
||||
|
|
@ -1376,9 +1370,9 @@ static inline int tcp_nagle_check(const struct tcp_sock *tp,
|
|||
const struct sk_buff *skb,
|
||||
unsigned mss_now, int nonagle)
|
||||
{
|
||||
return (skb->len < mss_now &&
|
||||
return skb->len < mss_now &&
|
||||
((nonagle & TCP_NAGLE_CORK) ||
|
||||
(!nonagle && tp->packets_out && tcp_minshall_check(tp))));
|
||||
(!nonagle && tp->packets_out && tcp_minshall_check(tp)));
|
||||
}
|
||||
|
||||
/* Return non-zero if the Nagle test allows this packet to be
|
||||
|
|
@ -1449,10 +1443,10 @@ int tcp_may_send_now(struct sock *sk)
|
|||
struct tcp_sock *tp = tcp_sk(sk);
|
||||
struct sk_buff *skb = tcp_send_head(sk);
|
||||
|
||||
return (skb &&
|
||||
return skb &&
|
||||
tcp_snd_test(sk, skb, tcp_current_mss(sk),
|
||||
(tcp_skb_is_last(sk, skb) ?
|
||||
tp->nonagle : TCP_NAGLE_PUSH)));
|
||||
tp->nonagle : TCP_NAGLE_PUSH));
|
||||
}
|
||||
|
||||
/* Trim TSO SKB to LEN bytes, put the remaining data into a new packet
|
||||
|
|
@ -2429,6 +2423,12 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
|
|||
__u8 rcv_wscale;
|
||||
/* Set this up on the first call only */
|
||||
req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
|
||||
|
||||
/* limit the window selection if the user enforce a smaller rx buffer */
|
||||
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
|
||||
(req->window_clamp > tcp_full_space(sk) || req->window_clamp == 0))
|
||||
req->window_clamp = tcp_full_space(sk);
|
||||
|
||||
/* tcp_full_space because it is guaranteed to be the first packet */
|
||||
tcp_select_initial_window(tcp_full_space(sk),
|
||||
mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
|
||||
|
|
@ -2555,6 +2555,11 @@ static void tcp_connect_init(struct sock *sk)
|
|||
|
||||
tcp_initialize_rcv_mss(sk);
|
||||
|
||||
/* limit the window selection if the user enforce a smaller rx buffer */
|
||||
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK &&
|
||||
(tp->window_clamp > tcp_full_space(sk) || tp->window_clamp == 0))
|
||||
tp->window_clamp = tcp_full_space(sk);
|
||||
|
||||
tcp_select_initial_window(tcp_full_space(sk),
|
||||
tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
|
||||
&tp->rcv_wnd,
|
||||
|
|
|
|||
|
|
@ -140,10 +140,10 @@ static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
|
|||
*/
|
||||
static bool retransmits_timed_out(struct sock *sk,
|
||||
unsigned int boundary,
|
||||
unsigned int timeout,
|
||||
bool syn_set)
|
||||
{
|
||||
unsigned int timeout, linear_backoff_thresh;
|
||||
unsigned int start_ts;
|
||||
unsigned int linear_backoff_thresh, start_ts;
|
||||
unsigned int rto_base = syn_set ? TCP_TIMEOUT_INIT : TCP_RTO_MIN;
|
||||
|
||||
if (!inet_csk(sk)->icsk_retransmits)
|
||||
|
|
@ -154,14 +154,15 @@ static bool retransmits_timed_out(struct sock *sk,
|
|||
else
|
||||
start_ts = tcp_sk(sk)->retrans_stamp;
|
||||
|
||||
linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base);
|
||||
|
||||
if (boundary <= linear_backoff_thresh)
|
||||
timeout = ((2 << boundary) - 1) * rto_base;
|
||||
else
|
||||
timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +
|
||||
(boundary - linear_backoff_thresh) * TCP_RTO_MAX;
|
||||
if (likely(timeout == 0)) {
|
||||
linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base);
|
||||
|
||||
if (boundary <= linear_backoff_thresh)
|
||||
timeout = ((2 << boundary) - 1) * rto_base;
|
||||
else
|
||||
timeout = ((2 << linear_backoff_thresh) - 1) * rto_base +
|
||||
(boundary - linear_backoff_thresh) * TCP_RTO_MAX;
|
||||
}
|
||||
return (tcp_time_stamp - start_ts) >= timeout;
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +179,7 @@ static int tcp_write_timeout(struct sock *sk)
|
|||
retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
|
||||
syn_set = 1;
|
||||
} else {
|
||||
if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0)) {
|
||||
if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0, 0)) {
|
||||
/* Black hole detection */
|
||||
tcp_mtu_probing(icsk, sk);
|
||||
|
||||
|
|
@ -191,14 +192,15 @@ static int tcp_write_timeout(struct sock *sk)
|
|||
|
||||
retry_until = tcp_orphan_retries(sk, alive);
|
||||
do_reset = alive ||
|
||||
!retransmits_timed_out(sk, retry_until, 0);
|
||||
!retransmits_timed_out(sk, retry_until, 0, 0);
|
||||
|
||||
if (tcp_out_of_resources(sk, do_reset))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (retransmits_timed_out(sk, retry_until, syn_set)) {
|
||||
if (retransmits_timed_out(sk, retry_until,
|
||||
syn_set ? 0 : icsk->icsk_user_timeout, syn_set)) {
|
||||
/* Has it gone just too far? */
|
||||
tcp_write_err(sk);
|
||||
return 1;
|
||||
|
|
@ -365,18 +367,19 @@ void tcp_retransmit_timer(struct sock *sk)
|
|||
if (icsk->icsk_retransmits == 0) {
|
||||
int mib_idx;
|
||||
|
||||
if (icsk->icsk_ca_state == TCP_CA_Disorder) {
|
||||
if (tcp_is_sack(tp))
|
||||
mib_idx = LINUX_MIB_TCPSACKFAILURES;
|
||||
else
|
||||
mib_idx = LINUX_MIB_TCPRENOFAILURES;
|
||||
} else if (icsk->icsk_ca_state == TCP_CA_Recovery) {
|
||||
if (icsk->icsk_ca_state == TCP_CA_Recovery) {
|
||||
if (tcp_is_sack(tp))
|
||||
mib_idx = LINUX_MIB_TCPSACKRECOVERYFAIL;
|
||||
else
|
||||
mib_idx = LINUX_MIB_TCPRENORECOVERYFAIL;
|
||||
} else if (icsk->icsk_ca_state == TCP_CA_Loss) {
|
||||
mib_idx = LINUX_MIB_TCPLOSSFAILURES;
|
||||
} else if ((icsk->icsk_ca_state == TCP_CA_Disorder) ||
|
||||
tp->sacked_out) {
|
||||
if (tcp_is_sack(tp))
|
||||
mib_idx = LINUX_MIB_TCPSACKFAILURES;
|
||||
else
|
||||
mib_idx = LINUX_MIB_TCPRENOFAILURES;
|
||||
} else {
|
||||
mib_idx = LINUX_MIB_TCPTIMEOUTS;
|
||||
}
|
||||
|
|
@ -440,7 +443,7 @@ out_reset_timer:
|
|||
icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
|
||||
}
|
||||
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX);
|
||||
if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0))
|
||||
if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1, 0, 0))
|
||||
__sk_dst_reset(sk);
|
||||
|
||||
out:;
|
||||
|
|
@ -560,7 +563,14 @@ static void tcp_keepalive_timer (unsigned long data)
|
|||
elapsed = keepalive_time_elapsed(tp);
|
||||
|
||||
if (elapsed >= keepalive_time_when(tp)) {
|
||||
if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
|
||||
/* If the TCP_USER_TIMEOUT option is enabled, use that
|
||||
* to determine when to timeout instead.
|
||||
*/
|
||||
if ((icsk->icsk_user_timeout != 0 &&
|
||||
elapsed >= icsk->icsk_user_timeout &&
|
||||
icsk->icsk_probes_out > 0) ||
|
||||
(icsk->icsk_user_timeout == 0 &&
|
||||
icsk->icsk_probes_out >= keepalive_probes(tp))) {
|
||||
tcp_send_active_reset(sk, GFP_ATOMIC);
|
||||
tcp_write_err(sk);
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ static void tcp_westwood_init(struct sock *sk)
|
|||
*/
|
||||
static inline u32 westwood_do_filter(u32 a, u32 b)
|
||||
{
|
||||
return (((7 * a) + b) >> 3);
|
||||
return ((7 * a) + b) >> 3;
|
||||
}
|
||||
|
||||
static void westwood_filter(struct westwood *w, u32 delta)
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@
|
|||
#include <net/protocol.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
static struct xfrm_tunnel *tunnel4_handlers;
|
||||
static struct xfrm_tunnel *tunnel64_handlers;
|
||||
static struct xfrm_tunnel *tunnel4_handlers __read_mostly;
|
||||
static struct xfrm_tunnel *tunnel64_handlers __read_mostly;
|
||||
static DEFINE_MUTEX(tunnel4_mutex);
|
||||
|
||||
static inline struct xfrm_tunnel **fam_handlers(unsigned short family)
|
||||
|
|
@ -39,7 +39,7 @@ int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
|
|||
}
|
||||
|
||||
handler->next = *pprev;
|
||||
*pprev = handler;
|
||||
rcu_assign_pointer(*pprev, handler);
|
||||
|
||||
ret = 0;
|
||||
|
||||
|
|
@ -73,6 +73,11 @@ int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family)
|
|||
}
|
||||
EXPORT_SYMBOL(xfrm4_tunnel_deregister);
|
||||
|
||||
#define for_each_tunnel_rcu(head, handler) \
|
||||
for (handler = rcu_dereference(head); \
|
||||
handler != NULL; \
|
||||
handler = rcu_dereference(handler->next)) \
|
||||
|
||||
static int tunnel4_rcv(struct sk_buff *skb)
|
||||
{
|
||||
struct xfrm_tunnel *handler;
|
||||
|
|
@ -80,7 +85,7 @@ static int tunnel4_rcv(struct sk_buff *skb)
|
|||
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
|
||||
goto drop;
|
||||
|
||||
for (handler = tunnel4_handlers; handler; handler = handler->next)
|
||||
for_each_tunnel_rcu(tunnel4_handlers, handler)
|
||||
if (!handler->handler(skb))
|
||||
return 0;
|
||||
|
||||
|
|
@ -99,7 +104,7 @@ static int tunnel64_rcv(struct sk_buff *skb)
|
|||
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
|
||||
goto drop;
|
||||
|
||||
for (handler = tunnel64_handlers; handler; handler = handler->next)
|
||||
for_each_tunnel_rcu(tunnel64_handlers, handler)
|
||||
if (!handler->handler(skb))
|
||||
return 0;
|
||||
|
||||
|
|
@ -115,7 +120,7 @@ static void tunnel4_err(struct sk_buff *skb, u32 info)
|
|||
{
|
||||
struct xfrm_tunnel *handler;
|
||||
|
||||
for (handler = tunnel4_handlers; handler; handler = handler->next)
|
||||
for_each_tunnel_rcu(tunnel4_handlers, handler)
|
||||
if (!handler->err_handler(skb, info))
|
||||
break;
|
||||
}
|
||||
|
|
@ -125,7 +130,7 @@ static void tunnel64_err(struct sk_buff *skb, u32 info)
|
|||
{
|
||||
struct xfrm_tunnel *handler;
|
||||
|
||||
for (handler = tunnel64_handlers; handler; handler = handler->next)
|
||||
for_each_tunnel_rcu(tunnel64_handlers, handler)
|
||||
if (!handler->err_handler(skb, info))
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -797,7 +797,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
ipc.opt = NULL;
|
||||
ipc.shtx.flags = 0;
|
||||
ipc.tx_flags = 0;
|
||||
|
||||
if (up->pending) {
|
||||
/*
|
||||
|
|
@ -845,7 +845,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
|||
ipc.addr = inet->inet_saddr;
|
||||
|
||||
ipc.oif = sk->sk_bound_dev_if;
|
||||
err = sock_tx_timestamp(msg, sk, &ipc.shtx);
|
||||
err = sock_tx_timestamp(sk, &ipc.tx_flags);
|
||||
if (err)
|
||||
return err;
|
||||
if (msg->msg_controllen) {
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ static inline int xfrm4_garbage_collect(struct dst_ops *ops)
|
|||
struct net *net = container_of(ops, struct net, xfrm.xfrm4_dst_ops);
|
||||
|
||||
xfrm4_policy_afinfo.garbage_collect(net);
|
||||
return (atomic_read(&ops->entries) > ops->gc_thresh * 2);
|
||||
return (dst_entries_get_slow(ops) > ops->gc_thresh * 2);
|
||||
}
|
||||
|
||||
static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)
|
||||
|
|
@ -232,7 +232,6 @@ static struct dst_ops xfrm4_dst_ops = {
|
|||
.ifdown = xfrm4_dst_ifdown,
|
||||
.local_out = __ip_local_out,
|
||||
.gc_thresh = 1024,
|
||||
.entries = ATOMIC_INIT(0),
|
||||
};
|
||||
|
||||
static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
|
||||
|
|
@ -288,6 +287,7 @@ void __init xfrm4_init(int rt_max_size)
|
|||
* and start cleaning when were 1/2 full
|
||||
*/
|
||||
xfrm4_dst_ops.gc_thresh = rt_max_size/2;
|
||||
dst_entries_init(&xfrm4_dst_ops);
|
||||
|
||||
xfrm4_state_init();
|
||||
xfrm4_policy_init();
|
||||
|
|
|
|||
|
|
@ -58,14 +58,14 @@ static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
static struct xfrm_tunnel xfrm_tunnel_handler = {
|
||||
static struct xfrm_tunnel xfrm_tunnel_handler __read_mostly = {
|
||||
.handler = xfrm_tunnel_rcv,
|
||||
.err_handler = xfrm_tunnel_err,
|
||||
.priority = 2,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
static struct xfrm_tunnel xfrm64_tunnel_handler = {
|
||||
static struct xfrm_tunnel xfrm64_tunnel_handler __read_mostly = {
|
||||
.handler = xfrm_tunnel_rcv,
|
||||
.err_handler = xfrm_tunnel_err,
|
||||
.priority = 2,
|
||||
|
|
|
|||
Loading…
Reference in a new issue