Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Resolve conflicts with conntrack template fixes. Conflicts: net/netfilter/nf_conntrack_core.c net/netfilter/nf_synproxy_core.c net/netfilter/xt_CT.c Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
@@ -119,6 +119,7 @@
|
||||
#ifdef CONFIG_IP_MROUTE
|
||||
#include <linux/mroute.h>
|
||||
#endif
|
||||
#include <net/vrf.h>
|
||||
|
||||
|
||||
/* The inetsw table contains everything that inet_create needs to
|
||||
@@ -427,6 +428,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||
struct net *net = sock_net(sk);
|
||||
unsigned short snum;
|
||||
int chk_addr_ret;
|
||||
int tb_id = RT_TABLE_LOCAL;
|
||||
int err;
|
||||
|
||||
/* If the socket has its own bind function then use it. (RAW) */
|
||||
@@ -448,7 +450,8 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||
goto out;
|
||||
}
|
||||
|
||||
chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr);
|
||||
tb_id = vrf_dev_table_ifindex(net, sk->sk_bound_dev_if) ? : tb_id;
|
||||
chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id);
|
||||
|
||||
/* Not specified by any standard per-se, however it breaks too
|
||||
* many applications when removed. It is unfortunate since
|
||||
|
@@ -233,7 +233,7 @@ static int arp_constructor(struct neighbour *neigh)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
neigh->type = inet_addr_type(dev_net(dev), addr);
|
||||
neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr);
|
||||
|
||||
parms = in_dev->arp_parms;
|
||||
__neigh_parms_put(neigh->parms);
|
||||
@@ -343,7 +343,7 @@ 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),
|
||||
if (skb && inet_addr_type_dev_table(dev_net(dev), dev,
|
||||
ip_hdr(skb)->saddr) == RTN_LOCAL)
|
||||
saddr = ip_hdr(skb)->saddr;
|
||||
break;
|
||||
@@ -351,7 +351,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
||||
if (!skb)
|
||||
break;
|
||||
saddr = ip_hdr(skb)->saddr;
|
||||
if (inet_addr_type(dev_net(dev), saddr) == RTN_LOCAL) {
|
||||
if (inet_addr_type_dev_table(dev_net(dev), dev,
|
||||
saddr) == RTN_LOCAL) {
|
||||
/* saddr should be known to target */
|
||||
if (inet_addr_onlink(in_dev, target, saddr))
|
||||
break;
|
||||
@@ -751,7 +752,7 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
|
||||
/* Special case: IPv4 duplicate address detection packet (RFC2131) */
|
||||
if (sip == 0) {
|
||||
if (arp->ar_op == htons(ARPOP_REQUEST) &&
|
||||
inet_addr_type(net, tip) == RTN_LOCAL &&
|
||||
inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&
|
||||
!arp_ignore(in_dev, sip, tip))
|
||||
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
|
||||
dev->dev_addr, sha);
|
||||
@@ -811,16 +812,18 @@ static int arp_process(struct sock *sk, struct sk_buff *skb)
|
||||
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
|
||||
|
||||
if (IN_DEV_ARP_ACCEPT(in_dev)) {
|
||||
unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip);
|
||||
|
||||
/* Unsolicited ARP is not accepted by default.
|
||||
It is possible, that this option should be enabled for some
|
||||
devices (strip is candidate)
|
||||
*/
|
||||
is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
|
||||
inet_addr_type(net, sip) == RTN_UNICAST;
|
||||
addr_type == RTN_UNICAST;
|
||||
|
||||
if (!n &&
|
||||
((arp->ar_op == htons(ARPOP_REPLY) &&
|
||||
inet_addr_type(net, sip) == RTN_UNICAST) || is_garp))
|
||||
addr_type == RTN_UNICAST) || is_garp))
|
||||
n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
|
||||
}
|
||||
|
||||
|
@@ -45,6 +45,7 @@
|
||||
#include <net/ip_fib.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/xfrm.h>
|
||||
#include <net/vrf.h>
|
||||
|
||||
#ifndef CONFIG_IP_MULTIPLE_TABLES
|
||||
|
||||
@@ -211,12 +212,12 @@ void fib_flush_external(struct net *net)
|
||||
*/
|
||||
static inline unsigned int __inet_dev_addr_type(struct net *net,
|
||||
const struct net_device *dev,
|
||||
__be32 addr)
|
||||
__be32 addr, int tb_id)
|
||||
{
|
||||
struct flowi4 fl4 = { .daddr = addr };
|
||||
struct fib_result res;
|
||||
unsigned int ret = RTN_BROADCAST;
|
||||
struct fib_table *local_table;
|
||||
struct fib_table *table;
|
||||
|
||||
if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
|
||||
return RTN_BROADCAST;
|
||||
@@ -225,10 +226,10 @@ static inline unsigned int __inet_dev_addr_type(struct net *net,
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
local_table = fib_get_table(net, RT_TABLE_LOCAL);
|
||||
if (local_table) {
|
||||
table = fib_get_table(net, tb_id);
|
||||
if (table) {
|
||||
ret = RTN_UNICAST;
|
||||
if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) {
|
||||
if (!fib_table_lookup(table, &fl4, &res, FIB_LOOKUP_NOREF)) {
|
||||
if (!dev || dev == res.fi->fib_dev)
|
||||
ret = res.type;
|
||||
}
|
||||
@@ -238,19 +239,40 @@ static inline unsigned int __inet_dev_addr_type(struct net *net,
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned int inet_addr_type_table(struct net *net, __be32 addr, int tb_id)
|
||||
{
|
||||
return __inet_dev_addr_type(net, NULL, addr, tb_id);
|
||||
}
|
||||
EXPORT_SYMBOL(inet_addr_type_table);
|
||||
|
||||
unsigned int inet_addr_type(struct net *net, __be32 addr)
|
||||
{
|
||||
return __inet_dev_addr_type(net, NULL, addr);
|
||||
return __inet_dev_addr_type(net, NULL, addr, RT_TABLE_LOCAL);
|
||||
}
|
||||
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);
|
||||
int rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL;
|
||||
|
||||
return __inet_dev_addr_type(net, dev, addr, rt_table);
|
||||
}
|
||||
EXPORT_SYMBOL(inet_dev_addr_type);
|
||||
|
||||
/* inet_addr_type with dev == NULL but using the table from a dev
|
||||
* if one is associated
|
||||
*/
|
||||
unsigned int inet_addr_type_dev_table(struct net *net,
|
||||
const struct net_device *dev,
|
||||
__be32 addr)
|
||||
{
|
||||
int rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL;
|
||||
|
||||
return __inet_dev_addr_type(net, NULL, addr, rt_table);
|
||||
}
|
||||
EXPORT_SYMBOL(inet_addr_type_dev_table);
|
||||
|
||||
__be32 fib_compute_spec_dst(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb->dev;
|
||||
@@ -309,7 +331,9 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
|
||||
bool dev_match;
|
||||
|
||||
fl4.flowi4_oif = 0;
|
||||
fl4.flowi4_iif = oif ? : LOOPBACK_IFINDEX;
|
||||
fl4.flowi4_iif = vrf_master_ifindex_rcu(dev);
|
||||
if (!fl4.flowi4_iif)
|
||||
fl4.flowi4_iif = oif ? : LOOPBACK_IFINDEX;
|
||||
fl4.daddr = src;
|
||||
fl4.saddr = dst;
|
||||
fl4.flowi4_tos = tos;
|
||||
@@ -339,6 +363,9 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
|
||||
if (nh->nh_dev == dev) {
|
||||
dev_match = true;
|
||||
break;
|
||||
} else if (vrf_master_ifindex_rcu(nh->nh_dev) == dev->ifindex) {
|
||||
dev_match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -496,9 +523,12 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
|
||||
|
||||
addr = sk_extract_addr(&rt->rt_gateway);
|
||||
if (rt->rt_gateway.sa_family == AF_INET && addr) {
|
||||
unsigned int addr_type;
|
||||
|
||||
cfg->fc_gw = addr;
|
||||
addr_type = inet_addr_type_table(net, addr, cfg->fc_table);
|
||||
if (rt->rt_flags & RTF_GATEWAY &&
|
||||
inet_addr_type(net, addr) == RTN_UNICAST)
|
||||
addr_type == RTN_UNICAST)
|
||||
cfg->fc_scope = RT_SCOPE_UNIVERSE;
|
||||
}
|
||||
|
||||
@@ -770,6 +800,7 @@ out:
|
||||
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);
|
||||
int tb_id = vrf_dev_table_rtnl(ifa->ifa_dev->dev);
|
||||
struct fib_table *tb;
|
||||
struct fib_config cfg = {
|
||||
.fc_protocol = RTPROT_KERNEL,
|
||||
@@ -784,11 +815,10 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
|
||||
},
|
||||
};
|
||||
|
||||
if (type == RTN_UNICAST)
|
||||
tb = fib_new_table(net, RT_TABLE_MAIN);
|
||||
else
|
||||
tb = fib_new_table(net, RT_TABLE_LOCAL);
|
||||
if (!tb_id)
|
||||
tb_id = (type == RTN_UNICAST) ? RT_TABLE_MAIN : RT_TABLE_LOCAL;
|
||||
|
||||
tb = fib_new_table(net, tb_id);
|
||||
if (!tb)
|
||||
return;
|
||||
|
||||
@@ -970,11 +1000,14 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
|
||||
fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
|
||||
}
|
||||
if (!(ok & LOCAL_OK)) {
|
||||
unsigned int addr_type;
|
||||
|
||||
fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
|
||||
|
||||
/* Check, that this local address finally disappeared. */
|
||||
if (gone &&
|
||||
inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
|
||||
addr_type = inet_addr_type_dev_table(dev_net(dev), dev,
|
||||
ifa->ifa_local);
|
||||
if (gone && addr_type != RTN_LOCAL) {
|
||||
/* And the last, but not the least thing.
|
||||
* We must flush stray FIB entries.
|
||||
*
|
||||
|
@@ -533,13 +533,13 @@ errout:
|
||||
|
||||
#endif
|
||||
|
||||
int fib_encap_match(struct net *net, u16 encap_type,
|
||||
struct nlattr *encap,
|
||||
int oif, const struct fib_nh *nh)
|
||||
static int fib_encap_match(struct net *net, u16 encap_type,
|
||||
struct nlattr *encap,
|
||||
int oif, const struct fib_nh *nh)
|
||||
{
|
||||
struct lwtunnel_state *lwtstate;
|
||||
struct net_device *dev = NULL;
|
||||
int ret;
|
||||
int ret, result = 0;
|
||||
|
||||
if (encap_type == LWTUNNEL_ENCAP_NONE)
|
||||
return 0;
|
||||
@@ -548,10 +548,12 @@ int fib_encap_match(struct net *net, u16 encap_type,
|
||||
dev = __dev_get_by_index(net, oif);
|
||||
ret = lwtunnel_build_state(dev, encap_type,
|
||||
encap, &lwtstate);
|
||||
if (!ret)
|
||||
return lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate);
|
||||
if (!ret) {
|
||||
result = lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate);
|
||||
lwtstate_free(lwtstate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
|
||||
@@ -670,16 +672,18 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
|
||||
struct fib_result res;
|
||||
|
||||
if (nh->nh_flags & RTNH_F_ONLINK) {
|
||||
unsigned int addr_type;
|
||||
|
||||
if (cfg->fc_scope >= RT_SCOPE_LINK)
|
||||
return -EINVAL;
|
||||
if (inet_addr_type(net, nh->nh_gw) != RTN_UNICAST)
|
||||
return -EINVAL;
|
||||
dev = __dev_get_by_index(net, nh->nh_oif);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (!(dev->flags & IFF_UP))
|
||||
return -ENETDOWN;
|
||||
addr_type = inet_addr_type_dev_table(net, dev, nh->nh_gw);
|
||||
if (addr_type != RTN_UNICAST)
|
||||
return -EINVAL;
|
||||
if (!netif_carrier_ok(dev))
|
||||
nh->nh_flags |= RTNH_F_LINKDOWN;
|
||||
nh->nh_dev = dev;
|
||||
@@ -689,6 +693,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
|
||||
}
|
||||
rcu_read_lock();
|
||||
{
|
||||
struct fib_table *tbl = NULL;
|
||||
struct flowi4 fl4 = {
|
||||
.daddr = nh->nh_gw,
|
||||
.flowi4_scope = cfg->fc_scope + 1,
|
||||
@@ -699,8 +704,24 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
|
||||
/* It is not necessary, but requires a bit of thinking */
|
||||
if (fl4.flowi4_scope < RT_SCOPE_LINK)
|
||||
fl4.flowi4_scope = RT_SCOPE_LINK;
|
||||
err = fib_lookup(net, &fl4, &res,
|
||||
FIB_LOOKUP_IGNORE_LINKSTATE);
|
||||
|
||||
if (cfg->fc_table)
|
||||
tbl = fib_get_table(net, cfg->fc_table);
|
||||
|
||||
if (tbl)
|
||||
err = fib_table_lookup(tbl, &fl4, &res,
|
||||
FIB_LOOKUP_IGNORE_LINKSTATE |
|
||||
FIB_LOOKUP_NOREF);
|
||||
|
||||
/* on error or if no table given do full lookup. This
|
||||
* is needed for example when nexthops are in the local
|
||||
* table rather than the given table
|
||||
*/
|
||||
if (!tbl || err) {
|
||||
err = fib_lookup(net, &fl4, &res,
|
||||
FIB_LOOKUP_IGNORE_LINKSTATE);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
@@ -836,6 +857,23 @@ __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh)
|
||||
return nh->nh_saddr;
|
||||
}
|
||||
|
||||
static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
|
||||
{
|
||||
if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
|
||||
fib_prefsrc != cfg->fc_dst) {
|
||||
int tb_id = cfg->fc_table;
|
||||
|
||||
if (tb_id == RT_TABLE_MAIN)
|
||||
tb_id = RT_TABLE_LOCAL;
|
||||
|
||||
if (inet_addr_type_table(cfg->fc_nlinfo.nl_net,
|
||||
fib_prefsrc, tb_id) != RTN_LOCAL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct fib_info *fib_create_info(struct fib_config *cfg)
|
||||
{
|
||||
int err;
|
||||
@@ -1031,12 +1069,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
|
||||
fi->fib_flags |= RTNH_F_LINKDOWN;
|
||||
}
|
||||
|
||||
if (fi->fib_prefsrc) {
|
||||
if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
|
||||
fi->fib_prefsrc != cfg->fc_dst)
|
||||
if (inet_addr_type(net, fi->fib_prefsrc) != RTN_LOCAL)
|
||||
goto err_inval;
|
||||
}
|
||||
if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc))
|
||||
goto err_inval;
|
||||
|
||||
change_nexthops(fi) {
|
||||
fib_info_update_nh_saddr(net, nexthop_nh);
|
||||
|
@@ -1423,8 +1423,11 @@ found:
|
||||
nh->nh_flags & RTNH_F_LINKDOWN &&
|
||||
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
|
||||
continue;
|
||||
if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
|
||||
continue;
|
||||
if (!(flp->flowi4_flags & FLOWI_FLAG_VRFSRC)) {
|
||||
if (flp->flowi4_oif &&
|
||||
flp->flowi4_oif != nh->nh_oif)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(fib_flags & FIB_LOOKUP_NOREF))
|
||||
atomic_inc(&fi->fib_clntref);
|
||||
|
@@ -31,7 +31,6 @@
|
||||
#include <net/xfrm.h>
|
||||
|
||||
static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
|
||||
static struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX];
|
||||
|
||||
int gre_add_protocol(const struct gre_protocol *proto, u8 version)
|
||||
{
|
||||
@@ -61,197 +60,6 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gre_del_protocol);
|
||||
|
||||
void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
|
||||
int hdr_len)
|
||||
{
|
||||
struct gre_base_hdr *greh;
|
||||
|
||||
skb_push(skb, hdr_len);
|
||||
|
||||
skb_reset_transport_header(skb);
|
||||
greh = (struct gre_base_hdr *)skb->data;
|
||||
greh->flags = tnl_flags_to_gre_flags(tpi->flags);
|
||||
greh->protocol = tpi->proto;
|
||||
|
||||
if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) {
|
||||
__be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
|
||||
|
||||
if (tpi->flags&TUNNEL_SEQ) {
|
||||
*ptr = tpi->seq;
|
||||
ptr--;
|
||||
}
|
||||
if (tpi->flags&TUNNEL_KEY) {
|
||||
*ptr = tpi->key;
|
||||
ptr--;
|
||||
}
|
||||
if (tpi->flags&TUNNEL_CSUM &&
|
||||
!(skb_shinfo(skb)->gso_type &
|
||||
(SKB_GSO_GRE|SKB_GSO_GRE_CSUM))) {
|
||||
*ptr = 0;
|
||||
*(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
|
||||
skb->len, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gre_build_header);
|
||||
|
||||
static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
|
||||
bool *csum_err)
|
||||
{
|
||||
const struct gre_base_hdr *greh;
|
||||
__be32 *options;
|
||||
int hdr_len;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
|
||||
return -EINVAL;
|
||||
|
||||
greh = (struct gre_base_hdr *)skb_transport_header(skb);
|
||||
if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
|
||||
return -EINVAL;
|
||||
|
||||
tpi->flags = gre_flags_to_tnl_flags(greh->flags);
|
||||
hdr_len = ip_gre_calc_hlen(tpi->flags);
|
||||
|
||||
if (!pskb_may_pull(skb, hdr_len))
|
||||
return -EINVAL;
|
||||
|
||||
greh = (struct gre_base_hdr *)skb_transport_header(skb);
|
||||
tpi->proto = greh->protocol;
|
||||
|
||||
options = (__be32 *)(greh + 1);
|
||||
if (greh->flags & GRE_CSUM) {
|
||||
if (skb_checksum_simple_validate(skb)) {
|
||||
*csum_err = true;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
|
||||
null_compute_pseudo);
|
||||
|
||||
options++;
|
||||
}
|
||||
|
||||
if (greh->flags & GRE_KEY) {
|
||||
tpi->key = *options;
|
||||
options++;
|
||||
} else
|
||||
tpi->key = 0;
|
||||
|
||||
if (unlikely(greh->flags & GRE_SEQ)) {
|
||||
tpi->seq = *options;
|
||||
options++;
|
||||
} else
|
||||
tpi->seq = 0;
|
||||
|
||||
/* WCCP version 1 and 2 protocol decoding.
|
||||
* - Change protocol to IP
|
||||
* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
|
||||
*/
|
||||
if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
|
||||
tpi->proto = htons(ETH_P_IP);
|
||||
if ((*(u8 *)options & 0xF0) != 0x40) {
|
||||
hdr_len += 4;
|
||||
if (!pskb_may_pull(skb, hdr_len))
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return iptunnel_pull_header(skb, hdr_len, tpi->proto);
|
||||
}
|
||||
|
||||
static int gre_cisco_rcv(struct sk_buff *skb)
|
||||
{
|
||||
struct tnl_ptk_info tpi;
|
||||
int i;
|
||||
bool csum_err = false;
|
||||
|
||||
#ifdef CONFIG_NET_IPGRE_BROADCAST
|
||||
if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
|
||||
/* Looped back packet, drop it! */
|
||||
if (rt_is_output_route(skb_rtable(skb)))
|
||||
goto drop;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (parse_gre_header(skb, &tpi, &csum_err) < 0)
|
||||
goto drop;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
|
||||
struct gre_cisco_protocol *proto;
|
||||
int ret;
|
||||
|
||||
proto = rcu_dereference(gre_cisco_proto_list[i]);
|
||||
if (!proto)
|
||||
continue;
|
||||
ret = proto->handler(skb, &tpi);
|
||||
if (ret == PACKET_RCVD) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gre_cisco_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
/* All the routers (except for Linux) return only
|
||||
* 8 bytes of packet payload. It means, that precise relaying of
|
||||
* ICMP in the real Internet is absolutely infeasible.
|
||||
*
|
||||
* Moreover, Cisco "wise men" put GRE key to the third word
|
||||
* in GRE header. It makes impossible maintaining even soft
|
||||
* state for keyed
|
||||
* GRE tunnels with enabled checksum. Tell them "thank you".
|
||||
*
|
||||
* Well, I wonder, rfc1812 was written by Cisco employee,
|
||||
* what the hell these idiots break standards established
|
||||
* by themselves???
|
||||
*/
|
||||
|
||||
const int type = icmp_hdr(skb)->type;
|
||||
const int code = icmp_hdr(skb)->code;
|
||||
struct tnl_ptk_info tpi;
|
||||
bool csum_err = false;
|
||||
int i;
|
||||
|
||||
if (parse_gre_header(skb, &tpi, &csum_err)) {
|
||||
if (!csum_err) /* ignore csum errors. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
||||
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
|
||||
skb->dev->ifindex, 0, IPPROTO_GRE, 0);
|
||||
return;
|
||||
}
|
||||
if (type == ICMP_REDIRECT) {
|
||||
ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0,
|
||||
IPPROTO_GRE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
|
||||
struct gre_cisco_protocol *proto;
|
||||
|
||||
proto = rcu_dereference(gre_cisco_proto_list[i]);
|
||||
if (!proto)
|
||||
continue;
|
||||
|
||||
if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD)
|
||||
goto out;
|
||||
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int gre_rcv(struct sk_buff *skb)
|
||||
{
|
||||
const struct gre_protocol *proto;
|
||||
@@ -302,60 +110,19 @@ static const struct net_protocol net_gre_protocol = {
|
||||
.netns_ok = 1,
|
||||
};
|
||||
|
||||
static const struct gre_protocol ipgre_protocol = {
|
||||
.handler = gre_cisco_rcv,
|
||||
.err_handler = gre_cisco_err,
|
||||
};
|
||||
|
||||
int gre_cisco_register(struct gre_cisco_protocol *newp)
|
||||
{
|
||||
struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
|
||||
&gre_cisco_proto_list[newp->priority];
|
||||
|
||||
return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gre_cisco_register);
|
||||
|
||||
int gre_cisco_unregister(struct gre_cisco_protocol *del_proto)
|
||||
{
|
||||
struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
|
||||
&gre_cisco_proto_list[del_proto->priority];
|
||||
int ret;
|
||||
|
||||
ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
synchronize_net();
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gre_cisco_unregister);
|
||||
|
||||
static int __init gre_init(void)
|
||||
{
|
||||
pr_info("GRE over IPv4 demultiplexor driver\n");
|
||||
|
||||
if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
|
||||
pr_err("can't add protocol\n");
|
||||
goto err;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) {
|
||||
pr_info("%s: can't add ipgre handler\n", __func__);
|
||||
goto err_gre;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_gre:
|
||||
inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
|
||||
err:
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static void __exit gre_exit(void)
|
||||
{
|
||||
gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
|
||||
inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
|
||||
}
|
||||
|
||||
|
@@ -96,6 +96,7 @@
|
||||
#include <net/xfrm.h>
|
||||
#include <net/inet_common.h>
|
||||
#include <net/ip_fib.h>
|
||||
#include <net/vrf.h>
|
||||
|
||||
/*
|
||||
* Build xmit assembly blocks
|
||||
@@ -425,6 +426,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
||||
fl4.flowi4_mark = mark;
|
||||
fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
|
||||
fl4.flowi4_proto = IPPROTO_ICMP;
|
||||
fl4.flowi4_oif = vrf_master_ifindex(skb->dev) ? : skb->dev->ifindex;
|
||||
security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
|
||||
rt = ip_route_output_key(net, &fl4);
|
||||
if (IS_ERR(rt))
|
||||
@@ -458,6 +460,8 @@ static struct rtable *icmp_route_lookup(struct net *net,
|
||||
fl4->flowi4_proto = IPPROTO_ICMP;
|
||||
fl4->fl4_icmp_type = type;
|
||||
fl4->fl4_icmp_code = code;
|
||||
fl4->flowi4_oif = vrf_master_ifindex(skb_in->dev) ? : skb_in->dev->ifindex;
|
||||
|
||||
security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4));
|
||||
rt = __ip_route_output_key(net, fl4);
|
||||
if (IS_ERR(rt))
|
||||
@@ -480,7 +484,8 @@ static struct rtable *icmp_route_lookup(struct net *net,
|
||||
if (err)
|
||||
goto relookup_failed;
|
||||
|
||||
if (inet_addr_type(net, fl4_dec.saddr) == RTN_LOCAL) {
|
||||
if (inet_addr_type_dev_table(net, skb_in->dev,
|
||||
fl4_dec.saddr) == RTN_LOCAL) {
|
||||
rt2 = __ip_route_output_key(net, &fl4_dec);
|
||||
if (IS_ERR(rt2))
|
||||
err = PTR_ERR(rt2);
|
||||
@@ -829,7 +834,7 @@ static bool icmp_unreach(struct sk_buff *skb)
|
||||
*/
|
||||
|
||||
if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
|
||||
inet_addr_type(net, iph->daddr) == RTN_BROADCAST) {
|
||||
inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) {
|
||||
net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n",
|
||||
&ip_hdr(skb)->saddr,
|
||||
icmph->type, icmph->code,
|
||||
|
@@ -593,7 +593,7 @@ static bool reqsk_queue_unlink(struct request_sock_queue *queue,
|
||||
}
|
||||
|
||||
spin_unlock(&queue->syn_wait_lock);
|
||||
if (del_timer(&req->rsk_timer))
|
||||
if (del_timer_sync(&req->rsk_timer))
|
||||
reqsk_put(req);
|
||||
return found;
|
||||
}
|
||||
|
@@ -48,6 +48,7 @@
|
||||
#include <linux/inet.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <net/inet_ecn.h>
|
||||
#include <net/vrf.h>
|
||||
|
||||
/* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6
|
||||
* code now. If you change something here, _PLEASE_ update ipv6/reassembly.c
|
||||
@@ -77,6 +78,7 @@ struct ipq {
|
||||
u8 ecn; /* RFC3168 support */
|
||||
u16 max_df_size; /* largest frag with DF set seen */
|
||||
int iif;
|
||||
int vif; /* VRF device index */
|
||||
unsigned int rid;
|
||||
struct inet_peer *peer;
|
||||
};
|
||||
@@ -99,6 +101,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
|
||||
struct ip4_create_arg {
|
||||
struct iphdr *iph;
|
||||
u32 user;
|
||||
int vif;
|
||||
};
|
||||
|
||||
static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
|
||||
@@ -127,7 +130,8 @@ static bool ip4_frag_match(const struct inet_frag_queue *q, const void *a)
|
||||
qp->saddr == arg->iph->saddr &&
|
||||
qp->daddr == arg->iph->daddr &&
|
||||
qp->protocol == arg->iph->protocol &&
|
||||
qp->user == arg->user;
|
||||
qp->user == arg->user &&
|
||||
qp->vif == arg->vif;
|
||||
}
|
||||
|
||||
static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
|
||||
@@ -144,6 +148,7 @@ static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
|
||||
qp->ecn = ip4_frag_ecn(arg->iph->tos);
|
||||
qp->saddr = arg->iph->saddr;
|
||||
qp->daddr = arg->iph->daddr;
|
||||
qp->vif = arg->vif;
|
||||
qp->user = arg->user;
|
||||
qp->peer = sysctl_ipfrag_max_dist ?
|
||||
inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, 1) : NULL;
|
||||
@@ -244,7 +249,8 @@ out:
|
||||
/* Find the correct entry in the "incomplete datagrams" queue for
|
||||
* this IP datagram, and create new one, if nothing is found.
|
||||
*/
|
||||
static struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
|
||||
static struct ipq *ip_find(struct net *net, struct iphdr *iph,
|
||||
u32 user, int vif)
|
||||
{
|
||||
struct inet_frag_queue *q;
|
||||
struct ip4_create_arg arg;
|
||||
@@ -252,6 +258,7 @@ static struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
|
||||
|
||||
arg.iph = iph;
|
||||
arg.user = user;
|
||||
arg.vif = vif;
|
||||
|
||||
hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
|
||||
|
||||
@@ -648,14 +655,15 @@ out_fail:
|
||||
/* Process an incoming IP datagram fragment. */
|
||||
int ip_defrag(struct sk_buff *skb, u32 user)
|
||||
{
|
||||
struct net_device *dev = skb->dev ? : skb_dst(skb)->dev;
|
||||
int vif = vrf_master_ifindex_rcu(dev);
|
||||
struct net *net = dev_net(dev);
|
||||
struct ipq *qp;
|
||||
struct net *net;
|
||||
|
||||
net = skb->dev ? dev_net(skb->dev) : dev_net(skb_dst(skb)->dev);
|
||||
IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS);
|
||||
|
||||
/* Lookup (or create) queue header */
|
||||
qp = ip_find(net, ip_hdr(skb), user);
|
||||
qp = ip_find(net, ip_hdr(skb), user, vif);
|
||||
if (qp) {
|
||||
int ret;
|
||||
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <linux/udp.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/mroute.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/inetdevice.h>
|
||||
@@ -47,6 +48,7 @@
|
||||
#include <net/netns/generic.h>
|
||||
#include <net/rtnetlink.h>
|
||||
#include <net/gre.h>
|
||||
#include <net/dst_metadata.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
#include <net/ipv6.h>
|
||||
@@ -121,8 +123,127 @@ static int ipgre_tunnel_init(struct net_device *dev);
|
||||
static int ipgre_net_id __read_mostly;
|
||||
static int gre_tap_net_id __read_mostly;
|
||||
|
||||
static int ipgre_err(struct sk_buff *skb, u32 info,
|
||||
const struct tnl_ptk_info *tpi)
|
||||
static int ip_gre_calc_hlen(__be16 o_flags)
|
||||
{
|
||||
int addend = 4;
|
||||
|
||||
if (o_flags & TUNNEL_CSUM)
|
||||
addend += 4;
|
||||
if (o_flags & TUNNEL_KEY)
|
||||
addend += 4;
|
||||
if (o_flags & TUNNEL_SEQ)
|
||||
addend += 4;
|
||||
return addend;
|
||||
}
|
||||
|
||||
static __be16 gre_flags_to_tnl_flags(__be16 flags)
|
||||
{
|
||||
__be16 tflags = 0;
|
||||
|
||||
if (flags & GRE_CSUM)
|
||||
tflags |= TUNNEL_CSUM;
|
||||
if (flags & GRE_ROUTING)
|
||||
tflags |= TUNNEL_ROUTING;
|
||||
if (flags & GRE_KEY)
|
||||
tflags |= TUNNEL_KEY;
|
||||
if (flags & GRE_SEQ)
|
||||
tflags |= TUNNEL_SEQ;
|
||||
if (flags & GRE_STRICT)
|
||||
tflags |= TUNNEL_STRICT;
|
||||
if (flags & GRE_REC)
|
||||
tflags |= TUNNEL_REC;
|
||||
if (flags & GRE_VERSION)
|
||||
tflags |= TUNNEL_VERSION;
|
||||
|
||||
return tflags;
|
||||
}
|
||||
|
||||
static __be16 tnl_flags_to_gre_flags(__be16 tflags)
|
||||
{
|
||||
__be16 flags = 0;
|
||||
|
||||
if (tflags & TUNNEL_CSUM)
|
||||
flags |= GRE_CSUM;
|
||||
if (tflags & TUNNEL_ROUTING)
|
||||
flags |= GRE_ROUTING;
|
||||
if (tflags & TUNNEL_KEY)
|
||||
flags |= GRE_KEY;
|
||||
if (tflags & TUNNEL_SEQ)
|
||||
flags |= GRE_SEQ;
|
||||
if (tflags & TUNNEL_STRICT)
|
||||
flags |= GRE_STRICT;
|
||||
if (tflags & TUNNEL_REC)
|
||||
flags |= GRE_REC;
|
||||
if (tflags & TUNNEL_VERSION)
|
||||
flags |= GRE_VERSION;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
|
||||
bool *csum_err)
|
||||
{
|
||||
const struct gre_base_hdr *greh;
|
||||
__be32 *options;
|
||||
int hdr_len;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
|
||||
return -EINVAL;
|
||||
|
||||
greh = (struct gre_base_hdr *)skb_transport_header(skb);
|
||||
if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
|
||||
return -EINVAL;
|
||||
|
||||
tpi->flags = gre_flags_to_tnl_flags(greh->flags);
|
||||
hdr_len = ip_gre_calc_hlen(tpi->flags);
|
||||
|
||||
if (!pskb_may_pull(skb, hdr_len))
|
||||
return -EINVAL;
|
||||
|
||||
greh = (struct gre_base_hdr *)skb_transport_header(skb);
|
||||
tpi->proto = greh->protocol;
|
||||
|
||||
options = (__be32 *)(greh + 1);
|
||||
if (greh->flags & GRE_CSUM) {
|
||||
if (skb_checksum_simple_validate(skb)) {
|
||||
*csum_err = true;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
|
||||
null_compute_pseudo);
|
||||
options++;
|
||||
}
|
||||
|
||||
if (greh->flags & GRE_KEY) {
|
||||
tpi->key = *options;
|
||||
options++;
|
||||
} else {
|
||||
tpi->key = 0;
|
||||
}
|
||||
if (unlikely(greh->flags & GRE_SEQ)) {
|
||||
tpi->seq = *options;
|
||||
options++;
|
||||
} else {
|
||||
tpi->seq = 0;
|
||||
}
|
||||
/* WCCP version 1 and 2 protocol decoding.
|
||||
* - Change protocol to IP
|
||||
* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
|
||||
*/
|
||||
if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
|
||||
tpi->proto = htons(ETH_P_IP);
|
||||
if ((*(u8 *)options & 0xF0) != 0x40) {
|
||||
hdr_len += 4;
|
||||
if (!pskb_may_pull(skb, hdr_len))
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return iptunnel_pull_header(skb, hdr_len, tpi->proto);
|
||||
}
|
||||
|
||||
static void ipgre_err(struct sk_buff *skb, u32 info,
|
||||
const struct tnl_ptk_info *tpi)
|
||||
{
|
||||
|
||||
/* All the routers (except for Linux) return only
|
||||
@@ -148,14 +269,14 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
|
||||
switch (type) {
|
||||
default:
|
||||
case ICMP_PARAMETERPROB:
|
||||
return PACKET_RCVD;
|
||||
return;
|
||||
|
||||
case ICMP_DEST_UNREACH:
|
||||
switch (code) {
|
||||
case ICMP_SR_FAILED:
|
||||
case ICMP_PORT_UNREACH:
|
||||
/* Impossible event. */
|
||||
return PACKET_RCVD;
|
||||
return;
|
||||
default:
|
||||
/* All others are translated to HOST_UNREACH.
|
||||
rfc2003 contains "deep thoughts" about NET_UNREACH,
|
||||
@@ -164,9 +285,10 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ICMP_TIME_EXCEEDED:
|
||||
if (code != ICMP_EXC_TTL)
|
||||
return PACKET_RCVD;
|
||||
return;
|
||||
break;
|
||||
|
||||
case ICMP_REDIRECT:
|
||||
@@ -183,26 +305,85 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
|
||||
iph->daddr, iph->saddr, tpi->key);
|
||||
|
||||
if (!t)
|
||||
return PACKET_REJECT;
|
||||
return;
|
||||
|
||||
if (t->parms.iph.daddr == 0 ||
|
||||
ipv4_is_multicast(t->parms.iph.daddr))
|
||||
return PACKET_RCVD;
|
||||
return;
|
||||
|
||||
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
|
||||
return PACKET_RCVD;
|
||||
return;
|
||||
|
||||
if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
|
||||
t->err_count++;
|
||||
else
|
||||
t->err_count = 1;
|
||||
t->err_time = jiffies;
|
||||
return PACKET_RCVD;
|
||||
}
|
||||
|
||||
static void gre_err(struct sk_buff *skb, u32 info)
|
||||
{
|
||||
/* All the routers (except for Linux) return only
|
||||
* 8 bytes of packet payload. It means, that precise relaying of
|
||||
* ICMP in the real Internet is absolutely infeasible.
|
||||
*
|
||||
* Moreover, Cisco "wise men" put GRE key to the third word
|
||||
* in GRE header. It makes impossible maintaining even soft
|
||||
* state for keyed
|
||||
* GRE tunnels with enabled checksum. Tell them "thank you".
|
||||
*
|
||||
* Well, I wonder, rfc1812 was written by Cisco employee,
|
||||
* what the hell these idiots break standards established
|
||||
* by themselves???
|
||||
*/
|
||||
|
||||
const int type = icmp_hdr(skb)->type;
|
||||
const int code = icmp_hdr(skb)->code;
|
||||
struct tnl_ptk_info tpi;
|
||||
bool csum_err = false;
|
||||
|
||||
if (parse_gre_header(skb, &tpi, &csum_err)) {
|
||||
if (!csum_err) /* ignore csum errors. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
|
||||
ipv4_update_pmtu(skb, dev_net(skb->dev), info,
|
||||
skb->dev->ifindex, 0, IPPROTO_GRE, 0);
|
||||
return;
|
||||
}
|
||||
if (type == ICMP_REDIRECT) {
|
||||
ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0,
|
||||
IPPROTO_GRE, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ipgre_err(skb, info, &tpi);
|
||||
}
|
||||
|
||||
static __be64 key_to_tunnel_id(__be32 key)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
return (__force __be64)((__force u32)key);
|
||||
#else
|
||||
return (__force __be64)((__force u64)key << 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns the least-significant 32 bits of a __be64. */
|
||||
static __be32 tunnel_id_to_key(__be64 x)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
return (__force __be32)x;
|
||||
#else
|
||||
return (__force __be32)((__force u64)x >> 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
|
||||
{
|
||||
struct net *net = dev_net(skb->dev);
|
||||
struct metadata_dst *tun_dst = NULL;
|
||||
struct ip_tunnel_net *itn;
|
||||
const struct iphdr *iph;
|
||||
struct ip_tunnel *tunnel;
|
||||
@@ -218,40 +399,194 @@ static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi)
|
||||
|
||||
if (tunnel) {
|
||||
skb_pop_mac_header(skb);
|
||||
ip_tunnel_rcv(tunnel, skb, tpi, log_ecn_error);
|
||||
if (tunnel->collect_md) {
|
||||
struct ip_tunnel_info *info;
|
||||
|
||||
tun_dst = metadata_dst_alloc(0, GFP_ATOMIC);
|
||||
if (!tun_dst)
|
||||
return PACKET_REJECT;
|
||||
|
||||
info = &tun_dst->u.tun_info;
|
||||
info->key.ipv4_src = iph->saddr;
|
||||
info->key.ipv4_dst = iph->daddr;
|
||||
info->key.ipv4_tos = iph->tos;
|
||||
info->key.ipv4_ttl = iph->ttl;
|
||||
|
||||
info->mode = IP_TUNNEL_INFO_RX;
|
||||
info->key.tun_flags = tpi->flags &
|
||||
(TUNNEL_CSUM | TUNNEL_KEY);
|
||||
info->key.tun_id = key_to_tunnel_id(tpi->key);
|
||||
|
||||
info->key.tp_src = 0;
|
||||
info->key.tp_dst = 0;
|
||||
}
|
||||
|
||||
ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
|
||||
return PACKET_RCVD;
|
||||
}
|
||||
return PACKET_REJECT;
|
||||
}
|
||||
|
||||
static int gre_rcv(struct sk_buff *skb)
|
||||
{
|
||||
struct tnl_ptk_info tpi;
|
||||
bool csum_err = false;
|
||||
|
||||
#ifdef CONFIG_NET_IPGRE_BROADCAST
|
||||
if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
|
||||
/* Looped back packet, drop it! */
|
||||
if (rt_is_output_route(skb_rtable(skb)))
|
||||
goto drop;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (parse_gre_header(skb, &tpi, &csum_err) < 0)
|
||||
goto drop;
|
||||
|
||||
if (ipgre_rcv(skb, &tpi) == PACKET_RCVD)
|
||||
return 0;
|
||||
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void build_header(struct sk_buff *skb, int hdr_len, __be16 flags,
|
||||
__be16 proto, __be32 key, __be32 seq)
|
||||
{
|
||||
struct gre_base_hdr *greh;
|
||||
|
||||
skb_push(skb, hdr_len);
|
||||
|
||||
skb_reset_transport_header(skb);
|
||||
greh = (struct gre_base_hdr *)skb->data;
|
||||
greh->flags = tnl_flags_to_gre_flags(flags);
|
||||
greh->protocol = proto;
|
||||
|
||||
if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) {
|
||||
__be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
|
||||
|
||||
if (flags & TUNNEL_SEQ) {
|
||||
*ptr = seq;
|
||||
ptr--;
|
||||
}
|
||||
if (flags & TUNNEL_KEY) {
|
||||
*ptr = key;
|
||||
ptr--;
|
||||
}
|
||||
if (flags & TUNNEL_CSUM &&
|
||||
!(skb_shinfo(skb)->gso_type &
|
||||
(SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) {
|
||||
*ptr = 0;
|
||||
*(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
|
||||
skb->len, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||
const struct iphdr *tnl_params,
|
||||
__be16 proto)
|
||||
{
|
||||
struct ip_tunnel *tunnel = netdev_priv(dev);
|
||||
struct tnl_ptk_info tpi;
|
||||
|
||||
tpi.flags = tunnel->parms.o_flags;
|
||||
tpi.proto = proto;
|
||||
tpi.key = tunnel->parms.o_key;
|
||||
if (tunnel->parms.o_flags & TUNNEL_SEQ)
|
||||
tunnel->o_seqno++;
|
||||
tpi.seq = htonl(tunnel->o_seqno);
|
||||
|
||||
/* Push GRE header. */
|
||||
gre_build_header(skb, &tpi, tunnel->tun_hlen);
|
||||
|
||||
skb_set_inner_protocol(skb, tpi.proto);
|
||||
build_header(skb, tunnel->tun_hlen, tunnel->parms.o_flags,
|
||||
proto, tunnel->parms.o_key, htonl(tunnel->o_seqno));
|
||||
|
||||
skb_set_inner_protocol(skb, proto);
|
||||
ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
|
||||
}
|
||||
|
||||
static struct sk_buff *gre_handle_offloads(struct sk_buff *skb,
|
||||
bool csum)
|
||||
{
|
||||
return iptunnel_handle_offloads(skb, csum,
|
||||
csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
|
||||
}
|
||||
|
||||
static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct ip_tunnel_info *tun_info;
|
||||
struct net *net = dev_net(dev);
|
||||
const struct ip_tunnel_key *key;
|
||||
struct flowi4 fl;
|
||||
struct rtable *rt;
|
||||
int min_headroom;
|
||||
int tunnel_hlen;
|
||||
__be16 df, flags;
|
||||
int err;
|
||||
|
||||
tun_info = skb_tunnel_info(skb, AF_INET);
|
||||
if (unlikely(!tun_info || tun_info->mode != IP_TUNNEL_INFO_TX))
|
||||
goto err_free_skb;
|
||||
|
||||
key = &tun_info->key;
|
||||
memset(&fl, 0, sizeof(fl));
|
||||
fl.daddr = key->ipv4_dst;
|
||||
fl.saddr = key->ipv4_src;
|
||||
fl.flowi4_tos = RT_TOS(key->ipv4_tos);
|
||||
fl.flowi4_mark = skb->mark;
|
||||
fl.flowi4_proto = IPPROTO_GRE;
|
||||
|
||||
rt = ip_route_output_key(net, &fl);
|
||||
if (IS_ERR(rt))
|
||||
goto err_free_skb;
|
||||
|
||||
tunnel_hlen = ip_gre_calc_hlen(key->tun_flags);
|
||||
|
||||
min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
|
||||
+ tunnel_hlen + sizeof(struct iphdr);
|
||||
if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) {
|
||||
int head_delta = SKB_DATA_ALIGN(min_headroom -
|
||||
skb_headroom(skb) +
|
||||
16);
|
||||
err = pskb_expand_head(skb, max_t(int, head_delta, 0),
|
||||
0, GFP_ATOMIC);
|
||||
if (unlikely(err))
|
||||
goto err_free_rt;
|
||||
}
|
||||
|
||||
/* Push Tunnel header. */
|
||||
skb = gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM));
|
||||
if (IS_ERR(skb)) {
|
||||
skb = NULL;
|
||||
goto err_free_rt;
|
||||
}
|
||||
|
||||
flags = tun_info->key.tun_flags & (TUNNEL_CSUM | TUNNEL_KEY);
|
||||
build_header(skb, tunnel_hlen, flags, htons(ETH_P_TEB),
|
||||
tunnel_id_to_key(tun_info->key.tun_id), 0);
|
||||
|
||||
df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0;
|
||||
err = iptunnel_xmit(skb->sk, rt, skb, fl.saddr,
|
||||
key->ipv4_dst, IPPROTO_GRE,
|
||||
key->ipv4_tos, key->ipv4_ttl, df, false);
|
||||
iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
|
||||
return;
|
||||
|
||||
err_free_rt:
|
||||
ip_rt_put(rt);
|
||||
err_free_skb:
|
||||
kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
}
|
||||
|
||||
static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct ip_tunnel *tunnel = netdev_priv(dev);
|
||||
const struct iphdr *tnl_params;
|
||||
|
||||
if (tunnel->collect_md) {
|
||||
gre_fb_xmit(skb, dev);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
if (dev->header_ops) {
|
||||
/* Need space for new headers */
|
||||
if (skb_cow_head(skb, dev->needed_headroom -
|
||||
@@ -277,7 +612,6 @@ static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
|
||||
goto out;
|
||||
|
||||
__gre_xmit(skb, dev, tnl_params, skb->protocol);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
free_skb:
|
||||
@@ -292,6 +626,11 @@ static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
|
||||
{
|
||||
struct ip_tunnel *tunnel = netdev_priv(dev);
|
||||
|
||||
if (tunnel->collect_md) {
|
||||
gre_fb_xmit(skb, dev);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM));
|
||||
if (IS_ERR(skb))
|
||||
goto out;
|
||||
@@ -300,7 +639,6 @@ static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
|
||||
goto free_skb;
|
||||
|
||||
__gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
free_skb:
|
||||
@@ -530,10 +868,9 @@ static int ipgre_tunnel_init(struct net_device *dev)
|
||||
return ip_tunnel_init(dev);
|
||||
}
|
||||
|
||||
static struct gre_cisco_protocol ipgre_protocol = {
|
||||
.handler = ipgre_rcv,
|
||||
.err_handler = ipgre_err,
|
||||
.priority = 0,
|
||||
static const struct gre_protocol ipgre_protocol = {
|
||||
.handler = gre_rcv,
|
||||
.err_handler = gre_err,
|
||||
};
|
||||
|
||||
static int __net_init ipgre_init_net(struct net *net)
|
||||
@@ -596,8 +933,10 @@ out:
|
||||
return ipgre_tunnel_validate(tb, data);
|
||||
}
|
||||
|
||||
static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[],
|
||||
struct ip_tunnel_parm *parms)
|
||||
static void ipgre_netlink_parms(struct net_device *dev,
|
||||
struct nlattr *data[],
|
||||
struct nlattr *tb[],
|
||||
struct ip_tunnel_parm *parms)
|
||||
{
|
||||
memset(parms, 0, sizeof(*parms));
|
||||
|
||||
@@ -635,6 +974,12 @@ static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[],
|
||||
|
||||
if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC]))
|
||||
parms->iph.frag_off = htons(IP_DF);
|
||||
|
||||
if (data[IFLA_GRE_COLLECT_METADATA]) {
|
||||
struct ip_tunnel *t = netdev_priv(dev);
|
||||
|
||||
t->collect_md = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function returns true when ENCAP attributes are present in the nl msg */
|
||||
@@ -712,7 +1057,7 @@ static int ipgre_newlink(struct net *src_net, struct net_device *dev,
|
||||
return err;
|
||||
}
|
||||
|
||||
ipgre_netlink_parms(data, tb, &p);
|
||||
ipgre_netlink_parms(dev, data, tb, &p);
|
||||
return ip_tunnel_newlink(dev, tb, &p);
|
||||
}
|
||||
|
||||
@@ -730,7 +1075,7 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
|
||||
return err;
|
||||
}
|
||||
|
||||
ipgre_netlink_parms(data, tb, &p);
|
||||
ipgre_netlink_parms(dev, data, tb, &p);
|
||||
return ip_tunnel_changelink(dev, tb, &p);
|
||||
}
|
||||
|
||||
@@ -765,6 +1110,8 @@ static size_t ipgre_get_size(const struct net_device *dev)
|
||||
nla_total_size(2) +
|
||||
/* IFLA_GRE_ENCAP_DPORT */
|
||||
nla_total_size(2) +
|
||||
/* IFLA_GRE_COLLECT_METADATA */
|
||||
nla_total_size(0) +
|
||||
0;
|
||||
}
|
||||
|
||||
@@ -796,6 +1143,11 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
||||
t->encap.flags))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (t->collect_md) {
|
||||
if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
@@ -817,6 +1169,7 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
|
||||
[IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 },
|
||||
[IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 },
|
||||
[IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 },
|
||||
[IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
|
||||
@@ -849,9 +1202,38 @@ static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
|
||||
.get_link_net = ip_tunnel_get_link_net,
|
||||
};
|
||||
|
||||
struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
|
||||
u8 name_assign_type)
|
||||
{
|
||||
struct nlattr *tb[IFLA_MAX + 1];
|
||||
struct net_device *dev;
|
||||
struct ip_tunnel *t;
|
||||
int err;
|
||||
|
||||
memset(&tb, 0, sizeof(tb));
|
||||
|
||||
dev = rtnl_create_link(net, name, name_assign_type,
|
||||
&ipgre_tap_ops, tb);
|
||||
if (IS_ERR(dev))
|
||||
return dev;
|
||||
|
||||
/* Configure flow based GRE device. */
|
||||
t = netdev_priv(dev);
|
||||
t->collect_md = true;
|
||||
|
||||
err = ipgre_newlink(net, dev, tb, NULL);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
return dev;
|
||||
out:
|
||||
free_netdev(dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gretap_fb_dev_create);
|
||||
|
||||
static int __net_init ipgre_tap_init_net(struct net *net)
|
||||
{
|
||||
return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, NULL);
|
||||
return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0");
|
||||
}
|
||||
|
||||
static void __net_exit ipgre_tap_exit_net(struct net *net)
|
||||
@@ -881,7 +1263,7 @@ static int __init ipgre_init(void)
|
||||
if (err < 0)
|
||||
goto pnet_tap_faied;
|
||||
|
||||
err = gre_cisco_register(&ipgre_protocol);
|
||||
err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
|
||||
if (err < 0) {
|
||||
pr_info("%s: can't add protocol\n", __func__);
|
||||
goto add_proto_failed;
|
||||
@@ -900,7 +1282,7 @@ static int __init ipgre_init(void)
|
||||
tap_ops_failed:
|
||||
rtnl_link_unregister(&ipgre_link_ops);
|
||||
rtnl_link_failed:
|
||||
gre_cisco_unregister(&ipgre_protocol);
|
||||
gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
|
||||
add_proto_failed:
|
||||
unregister_pernet_device(&ipgre_tap_net_ops);
|
||||
pnet_tap_faied:
|
||||
@@ -912,7 +1294,7 @@ static void __exit ipgre_fini(void)
|
||||
{
|
||||
rtnl_link_unregister(&ipgre_tap_ops);
|
||||
rtnl_link_unregister(&ipgre_link_ops);
|
||||
gre_cisco_unregister(&ipgre_protocol);
|
||||
gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
|
||||
unregister_pernet_device(&ipgre_tap_net_ops);
|
||||
unregister_pernet_device(&ipgre_net_ops);
|
||||
}
|
||||
|
@@ -1542,6 +1542,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
|
||||
struct net *net = sock_net(sk);
|
||||
struct sk_buff *nskb;
|
||||
int err;
|
||||
int oif;
|
||||
|
||||
if (__ip_options_echo(&replyopts.opt.opt, skb, sopt))
|
||||
return;
|
||||
@@ -1559,7 +1560,11 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
|
||||
daddr = replyopts.opt.opt.faddr;
|
||||
}
|
||||
|
||||
flowi4_init_output(&fl4, arg->bound_dev_if,
|
||||
oif = arg->bound_dev_if;
|
||||
if (!oif && netif_index_is_vrf(net, skb->skb_iif))
|
||||
oif = skb->skb_iif;
|
||||
|
||||
flowi4_init_output(&fl4, oif,
|
||||
IP4_REPLY_MARK(net, skb->mark),
|
||||
RT_TOS(arg->tos),
|
||||
RT_SCOPE_UNIVERSE, ip_hdr(skb)->protocol,
|
||||
|
@@ -230,10 +230,13 @@ skip_key_lookup:
|
||||
if (cand)
|
||||
return cand;
|
||||
|
||||
t = rcu_dereference(itn->collect_md_tun);
|
||||
if (t)
|
||||
return t;
|
||||
|
||||
if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP)
|
||||
return netdev_priv(itn->fb_tunnel_dev);
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_tunnel_lookup);
|
||||
@@ -261,11 +264,15 @@ static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t)
|
||||
{
|
||||
struct hlist_head *head = ip_bucket(itn, &t->parms);
|
||||
|
||||
if (t->collect_md)
|
||||
rcu_assign_pointer(itn->collect_md_tun, t);
|
||||
hlist_add_head_rcu(&t->hash_node, head);
|
||||
}
|
||||
|
||||
static void ip_tunnel_del(struct ip_tunnel *t)
|
||||
static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t)
|
||||
{
|
||||
if (t->collect_md)
|
||||
rcu_assign_pointer(itn->collect_md_tun, NULL);
|
||||
hlist_del_init_rcu(&t->hash_node);
|
||||
}
|
||||
|
||||
@@ -419,7 +426,8 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net,
|
||||
}
|
||||
|
||||
int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
|
||||
const struct tnl_ptk_info *tpi, bool log_ecn_error)
|
||||
const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst,
|
||||
bool log_ecn_error)
|
||||
{
|
||||
struct pcpu_sw_netstats *tstats;
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
@@ -478,6 +486,9 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
|
||||
skb->dev = tunnel->dev;
|
||||
}
|
||||
|
||||
if (tun_dst)
|
||||
skb_dst_set(skb, (struct dst_entry *)tun_dst);
|
||||
|
||||
gro_cells_receive(&tunnel->gro_cells, skb);
|
||||
return 0;
|
||||
|
||||
@@ -806,7 +817,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
|
||||
struct ip_tunnel_parm *p,
|
||||
bool set_mtu)
|
||||
{
|
||||
ip_tunnel_del(t);
|
||||
ip_tunnel_del(itn, t);
|
||||
t->parms.iph.saddr = p->iph.saddr;
|
||||
t->parms.iph.daddr = p->iph.daddr;
|
||||
t->parms.i_key = p->i_key;
|
||||
@@ -967,7 +978,7 @@ void ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
|
||||
itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id);
|
||||
|
||||
if (itn->fb_tunnel_dev != dev) {
|
||||
ip_tunnel_del(netdev_priv(dev));
|
||||
ip_tunnel_del(itn, netdev_priv(dev));
|
||||
unregister_netdevice_queue(dev, head);
|
||||
}
|
||||
}
|
||||
@@ -1072,8 +1083,13 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
|
||||
nt = netdev_priv(dev);
|
||||
itn = net_generic(net, nt->ip_tnl_net_id);
|
||||
|
||||
if (ip_tunnel_find(itn, p, dev->type))
|
||||
return -EEXIST;
|
||||
if (nt->collect_md) {
|
||||
if (rtnl_dereference(itn->collect_md_tun))
|
||||
return -EEXIST;
|
||||
} else {
|
||||
if (ip_tunnel_find(itn, p, dev->type))
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
nt->net = net;
|
||||
nt->parms = *p;
|
||||
@@ -1089,7 +1105,6 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
|
||||
dev->mtu = mtu;
|
||||
|
||||
ip_tunnel_add(itn, nt);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
@@ -1163,6 +1178,10 @@ int ip_tunnel_init(struct net_device *dev)
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
|
||||
if (tunnel->collect_md) {
|
||||
dev->features |= NETIF_F_NETNS_LOCAL;
|
||||
netif_keep_dst(dev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_tunnel_init);
|
||||
@@ -1176,7 +1195,7 @@ void ip_tunnel_uninit(struct net_device *dev)
|
||||
itn = net_generic(net, tunnel->ip_tnl_net_id);
|
||||
/* fb_tunnel_dev will be unregisted in net-exit call. */
|
||||
if (itn->fb_tunnel_dev != dev)
|
||||
ip_tunnel_del(netdev_priv(dev));
|
||||
ip_tunnel_del(itn, netdev_priv(dev));
|
||||
|
||||
ip_tunnel_dst_reset_all(tunnel);
|
||||
}
|
||||
|
@@ -192,15 +192,15 @@ struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
|
||||
|
||||
static const struct nla_policy ip_tun_policy[IP_TUN_MAX + 1] = {
|
||||
[IP_TUN_ID] = { .type = NLA_U64 },
|
||||
[IP_TUN_DST] = { .type = NLA_U32 },
|
||||
[IP_TUN_SRC] = { .type = NLA_U32 },
|
||||
[IP_TUN_TTL] = { .type = NLA_U8 },
|
||||
[IP_TUN_TOS] = { .type = NLA_U8 },
|
||||
[IP_TUN_SPORT] = { .type = NLA_U16 },
|
||||
[IP_TUN_DPORT] = { .type = NLA_U16 },
|
||||
[IP_TUN_FLAGS] = { .type = NLA_U16 },
|
||||
static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = {
|
||||
[LWTUNNEL_IP_ID] = { .type = NLA_U64 },
|
||||
[LWTUNNEL_IP_DST] = { .type = NLA_U32 },
|
||||
[LWTUNNEL_IP_SRC] = { .type = NLA_U32 },
|
||||
[LWTUNNEL_IP_TTL] = { .type = NLA_U8 },
|
||||
[LWTUNNEL_IP_TOS] = { .type = NLA_U8 },
|
||||
[LWTUNNEL_IP_SPORT] = { .type = NLA_U16 },
|
||||
[LWTUNNEL_IP_DPORT] = { .type = NLA_U16 },
|
||||
[LWTUNNEL_IP_FLAGS] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr,
|
||||
@@ -208,10 +208,10 @@ static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr,
|
||||
{
|
||||
struct ip_tunnel_info *tun_info;
|
||||
struct lwtunnel_state *new_state;
|
||||
struct nlattr *tb[IP_TUN_MAX + 1];
|
||||
struct nlattr *tb[LWTUNNEL_IP_MAX + 1];
|
||||
int err;
|
||||
|
||||
err = nla_parse_nested(tb, IP_TUN_MAX, attr, ip_tun_policy);
|
||||
err = nla_parse_nested(tb, LWTUNNEL_IP_MAX, attr, ip_tun_policy);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
@@ -223,29 +223,29 @@ static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr,
|
||||
|
||||
tun_info = lwt_tun_info(new_state);
|
||||
|
||||
if (tb[IP_TUN_ID])
|
||||
tun_info->key.tun_id = nla_get_u64(tb[IP_TUN_ID]);
|
||||
if (tb[LWTUNNEL_IP_ID])
|
||||
tun_info->key.tun_id = nla_get_u64(tb[LWTUNNEL_IP_ID]);
|
||||
|
||||
if (tb[IP_TUN_DST])
|
||||
tun_info->key.ipv4_dst = nla_get_be32(tb[IP_TUN_DST]);
|
||||
if (tb[LWTUNNEL_IP_DST])
|
||||
tun_info->key.ipv4_dst = nla_get_be32(tb[LWTUNNEL_IP_DST]);
|
||||
|
||||
if (tb[IP_TUN_SRC])
|
||||
tun_info->key.ipv4_src = nla_get_be32(tb[IP_TUN_SRC]);
|
||||
if (tb[LWTUNNEL_IP_SRC])
|
||||
tun_info->key.ipv4_src = nla_get_be32(tb[LWTUNNEL_IP_SRC]);
|
||||
|
||||
if (tb[IP_TUN_TTL])
|
||||
tun_info->key.ipv4_ttl = nla_get_u8(tb[IP_TUN_TTL]);
|
||||
if (tb[LWTUNNEL_IP_TTL])
|
||||
tun_info->key.ipv4_ttl = nla_get_u8(tb[LWTUNNEL_IP_TTL]);
|
||||
|
||||
if (tb[IP_TUN_TOS])
|
||||
tun_info->key.ipv4_tos = nla_get_u8(tb[IP_TUN_TOS]);
|
||||
if (tb[LWTUNNEL_IP_TOS])
|
||||
tun_info->key.ipv4_tos = nla_get_u8(tb[LWTUNNEL_IP_TOS]);
|
||||
|
||||
if (tb[IP_TUN_SPORT])
|
||||
tun_info->key.tp_src = nla_get_be16(tb[IP_TUN_SPORT]);
|
||||
if (tb[LWTUNNEL_IP_SPORT])
|
||||
tun_info->key.tp_src = nla_get_be16(tb[LWTUNNEL_IP_SPORT]);
|
||||
|
||||
if (tb[IP_TUN_DPORT])
|
||||
tun_info->key.tp_dst = nla_get_be16(tb[IP_TUN_DPORT]);
|
||||
if (tb[LWTUNNEL_IP_DPORT])
|
||||
tun_info->key.tp_dst = nla_get_be16(tb[LWTUNNEL_IP_DPORT]);
|
||||
|
||||
if (tb[IP_TUN_FLAGS])
|
||||
tun_info->key.tun_flags = nla_get_u16(tb[IP_TUN_FLAGS]);
|
||||
if (tb[LWTUNNEL_IP_FLAGS])
|
||||
tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP_FLAGS]);
|
||||
|
||||
tun_info->mode = IP_TUNNEL_INFO_TX;
|
||||
tun_info->options = NULL;
|
||||
@@ -261,14 +261,14 @@ static int ip_tun_fill_encap_info(struct sk_buff *skb,
|
||||
{
|
||||
struct ip_tunnel_info *tun_info = lwt_tun_info(lwtstate);
|
||||
|
||||
if (nla_put_u64(skb, IP_TUN_ID, tun_info->key.tun_id) ||
|
||||
nla_put_be32(skb, IP_TUN_DST, tun_info->key.ipv4_dst) ||
|
||||
nla_put_be32(skb, IP_TUN_SRC, tun_info->key.ipv4_src) ||
|
||||
nla_put_u8(skb, IP_TUN_TOS, tun_info->key.ipv4_tos) ||
|
||||
nla_put_u8(skb, IP_TUN_TTL, tun_info->key.ipv4_ttl) ||
|
||||
nla_put_u16(skb, IP_TUN_SPORT, tun_info->key.tp_src) ||
|
||||
nla_put_u16(skb, IP_TUN_DPORT, tun_info->key.tp_dst) ||
|
||||
nla_put_u16(skb, IP_TUN_FLAGS, tun_info->key.tun_flags))
|
||||
if (nla_put_u64(skb, LWTUNNEL_IP_ID, tun_info->key.tun_id) ||
|
||||
nla_put_be32(skb, LWTUNNEL_IP_DST, tun_info->key.ipv4_dst) ||
|
||||
nla_put_be32(skb, LWTUNNEL_IP_SRC, tun_info->key.ipv4_src) ||
|
||||
nla_put_u8(skb, LWTUNNEL_IP_TOS, tun_info->key.ipv4_tos) ||
|
||||
nla_put_u8(skb, LWTUNNEL_IP_TTL, tun_info->key.ipv4_ttl) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP_SPORT, tun_info->key.tp_src) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP_DPORT, tun_info->key.tp_dst) ||
|
||||
nla_put_u16(skb, LWTUNNEL_IP_FLAGS, tun_info->key.tun_flags))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
@@ -276,20 +276,27 @@ static int ip_tun_fill_encap_info(struct sk_buff *skb,
|
||||
|
||||
static int ip_tun_encap_nlsize(struct lwtunnel_state *lwtstate)
|
||||
{
|
||||
return nla_total_size(8) /* IP_TUN_ID */
|
||||
+ nla_total_size(4) /* IP_TUN_DST */
|
||||
+ nla_total_size(4) /* IP_TUN_SRC */
|
||||
+ nla_total_size(1) /* IP_TUN_TOS */
|
||||
+ nla_total_size(1) /* IP_TUN_TTL */
|
||||
+ nla_total_size(2) /* IP_TUN_SPORT */
|
||||
+ nla_total_size(2) /* IP_TUN_DPORT */
|
||||
+ nla_total_size(2); /* IP_TUN_FLAGS */
|
||||
return nla_total_size(8) /* LWTUNNEL_IP_ID */
|
||||
+ nla_total_size(4) /* LWTUNNEL_IP_DST */
|
||||
+ nla_total_size(4) /* LWTUNNEL_IP_SRC */
|
||||
+ nla_total_size(1) /* LWTUNNEL_IP_TOS */
|
||||
+ nla_total_size(1) /* LWTUNNEL_IP_TTL */
|
||||
+ nla_total_size(2) /* LWTUNNEL_IP_SPORT */
|
||||
+ nla_total_size(2) /* LWTUNNEL_IP_DPORT */
|
||||
+ nla_total_size(2); /* LWTUNNEL_IP_FLAGS */
|
||||
}
|
||||
|
||||
static int ip_tun_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b)
|
||||
{
|
||||
return memcmp(lwt_tun_info(a), lwt_tun_info(b),
|
||||
sizeof(struct ip_tunnel_info));
|
||||
}
|
||||
|
||||
static const struct lwtunnel_encap_ops ip_tun_lwt_ops = {
|
||||
.build_state = ip_tun_build_state,
|
||||
.fill_encap = ip_tun_fill_encap_info,
|
||||
.get_encap_size = ip_tun_encap_nlsize,
|
||||
.cmp_encap = ip_tun_cmp_encap,
|
||||
};
|
||||
|
||||
void __init ip_tunnel_core_init(void)
|
||||
|
@@ -94,7 +94,7 @@
|
||||
/* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
|
||||
#define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */
|
||||
#define CONF_SEND_RETRIES 6 /* Send six requests per open */
|
||||
#define CONF_INTER_TIMEOUT (HZ/2) /* Inter-device timeout: 1/2 second */
|
||||
#define CONF_INTER_TIMEOUT (HZ) /* Inter-device timeout: 1 second */
|
||||
#define CONF_BASE_TIMEOUT (HZ*2) /* Initial timeout: 2 seconds */
|
||||
#define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */
|
||||
#define CONF_TIMEOUT_MULT *7/4 /* Rate of timeout growth */
|
||||
|
@@ -198,7 +198,7 @@ static int ipip_rcv(struct sk_buff *skb)
|
||||
goto drop;
|
||||
if (iptunnel_pull_header(skb, 0, tpi.proto))
|
||||
goto drop;
|
||||
return ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error);
|
||||
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error);
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@@ -72,7 +72,7 @@ set_ect_tcp(struct sk_buff *skb, const struct ipt_ECN_info *einfo)
|
||||
tcph->cwr = einfo->proto.tcp.cwr;
|
||||
|
||||
inet_proto_csum_replace2(&tcph->check, skb,
|
||||
oldval, ((__be16 *)tcph)[6], 0);
|
||||
oldval, ((__be16 *)tcph)[6], false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -226,7 +226,8 @@ synproxy_send_client_ack(const struct synproxy_net *snet,
|
||||
|
||||
synproxy_build_options(nth, opts);
|
||||
|
||||
synproxy_send_tcp(skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
|
||||
synproxy_send_tcp(skb, nskb, skb->nfct, IP_CT_ESTABLISHED_REPLY,
|
||||
niph, nth, tcp_hdr_size);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@@ -120,7 +120,7 @@ static void nf_nat_ipv4_csum_update(struct sk_buff *skb,
|
||||
oldip = iph->daddr;
|
||||
newip = t->dst.u3.ip;
|
||||
}
|
||||
inet_proto_csum_replace4(check, skb, oldip, newip, 1);
|
||||
inet_proto_csum_replace4(check, skb, oldip, newip, true);
|
||||
}
|
||||
|
||||
static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
|
||||
@@ -151,7 +151,7 @@ static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
|
||||
}
|
||||
} else
|
||||
inet_proto_csum_replace2(check, skb,
|
||||
htons(oldlen), htons(datalen), 1);
|
||||
htons(oldlen), htons(datalen), true);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
|
||||
|
@@ -67,7 +67,7 @@ icmp_manip_pkt(struct sk_buff *skb,
|
||||
|
||||
hdr = (struct icmphdr *)(skb->data + hdroff);
|
||||
inet_proto_csum_replace2(&hdr->checksum, skb,
|
||||
hdr->un.echo.id, tuple->src.u.icmp.id, 0);
|
||||
hdr->un.echo.id, tuple->src.u.icmp.id, false);
|
||||
hdr->un.echo.id = tuple->src.u.icmp.id;
|
||||
return true;
|
||||
}
|
||||
|
@@ -112,6 +112,7 @@
|
||||
#endif
|
||||
#include <net/secure_seq.h>
|
||||
#include <net/ip_tunnels.h>
|
||||
#include <net/vrf.h>
|
||||
|
||||
#define RT_FL_TOS(oldflp4) \
|
||||
((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))
|
||||
@@ -1630,8 +1631,14 @@ static int __mkroute_input(struct sk_buff *skb,
|
||||
rth->dst.output = ip_output;
|
||||
|
||||
rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag);
|
||||
if (lwtunnel_output_redirect(rth->rt_lwtstate))
|
||||
if (lwtunnel_output_redirect(rth->rt_lwtstate)) {
|
||||
rth->rt_lwtstate->orig_output = rth->dst.output;
|
||||
rth->dst.output = lwtunnel_output;
|
||||
}
|
||||
if (lwtunnel_input_redirect(rth->rt_lwtstate)) {
|
||||
rth->rt_lwtstate->orig_input = rth->dst.input;
|
||||
rth->dst.input = lwtunnel_input;
|
||||
}
|
||||
skb_dst_set(skb, &rth->dst);
|
||||
out:
|
||||
err = 0;
|
||||
@@ -1726,7 +1733,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
|
||||
* Now we are ready to route packet.
|
||||
*/
|
||||
fl4.flowi4_oif = 0;
|
||||
fl4.flowi4_iif = dev->ifindex;
|
||||
fl4.flowi4_iif = vrf_master_ifindex_rcu(dev) ? : dev->ifindex;
|
||||
fl4.flowi4_mark = skb->mark;
|
||||
fl4.flowi4_tos = tos;
|
||||
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
|
||||
@@ -2130,6 +2137,11 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
|
||||
fl4->saddr = inet_select_addr(dev_out, 0,
|
||||
RT_SCOPE_HOST);
|
||||
}
|
||||
if (netif_is_vrf(dev_out) &&
|
||||
!(fl4->flowi4_flags & FLOWI_FLAG_VRFSRC)) {
|
||||
rth = vrf_dev_get_rth(dev_out);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fl4->daddr) {
|
||||
|
@@ -1348,7 +1348,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
|
||||
req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr);
|
||||
if (req) {
|
||||
nsk = tcp_check_req(sk, skb, req, false);
|
||||
if (!nsk)
|
||||
if (!nsk || nsk == sk)
|
||||
reqsk_put(req);
|
||||
return nsk;
|
||||
}
|
||||
|
@@ -2149,7 +2149,7 @@ repair:
|
||||
tcp_cwnd_validate(sk, is_cwnd_limited);
|
||||
return false;
|
||||
}
|
||||
return (push_one == 2) || (!tp->packets_out && tcp_send_head(sk));
|
||||
return !tp->packets_out && tcp_send_head(sk);
|
||||
}
|
||||
|
||||
bool tcp_schedule_loss_probe(struct sock *sk)
|
||||
@@ -2226,7 +2226,7 @@ static bool skb_still_in_host_queue(const struct sock *sk,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* When probe timeout (PTO) fires, send a new segment if one exists, else
|
||||
/* When probe timeout (PTO) fires, try send a new segment if possible, else
|
||||
* retransmit the last segment.
|
||||
*/
|
||||
void tcp_send_loss_probe(struct sock *sk)
|
||||
@@ -2235,11 +2235,19 @@ void tcp_send_loss_probe(struct sock *sk)
|
||||
struct sk_buff *skb;
|
||||
int pcount;
|
||||
int mss = tcp_current_mss(sk);
|
||||
int err = -1;
|
||||
|
||||
if (tcp_send_head(sk)) {
|
||||
err = tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC);
|
||||
goto rearm_timer;
|
||||
skb = tcp_send_head(sk);
|
||||
if (skb) {
|
||||
if (tcp_snd_wnd_test(tp, skb, mss)) {
|
||||
pcount = tp->packets_out;
|
||||
tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC);
|
||||
if (tp->packets_out > pcount)
|
||||
goto probe_sent;
|
||||
goto rearm_timer;
|
||||
}
|
||||
skb = tcp_write_queue_prev(sk, skb);
|
||||
} else {
|
||||
skb = tcp_write_queue_tail(sk);
|
||||
}
|
||||
|
||||
/* At most one outstanding TLP retransmission. */
|
||||
@@ -2247,7 +2255,6 @@ void tcp_send_loss_probe(struct sock *sk)
|
||||
goto rearm_timer;
|
||||
|
||||
/* Retransmit last segment. */
|
||||
skb = tcp_write_queue_tail(sk);
|
||||
if (WARN_ON(!skb))
|
||||
goto rearm_timer;
|
||||
|
||||
@@ -2262,26 +2269,24 @@ void tcp_send_loss_probe(struct sock *sk)
|
||||
if (unlikely(tcp_fragment(sk, skb, (pcount - 1) * mss, mss,
|
||||
GFP_ATOMIC)))
|
||||
goto rearm_timer;
|
||||
skb = tcp_write_queue_tail(sk);
|
||||
skb = tcp_write_queue_next(sk, skb);
|
||||
}
|
||||
|
||||
if (WARN_ON(!skb || !tcp_skb_pcount(skb)))
|
||||
goto rearm_timer;
|
||||
|
||||
err = __tcp_retransmit_skb(sk, skb);
|
||||
if (__tcp_retransmit_skb(sk, skb))
|
||||
goto rearm_timer;
|
||||
|
||||
/* Record snd_nxt for loss detection. */
|
||||
if (likely(!err))
|
||||
tp->tlp_high_seq = tp->snd_nxt;
|
||||
tp->tlp_high_seq = tp->snd_nxt;
|
||||
|
||||
probe_sent:
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSSPROBES);
|
||||
/* Reset s.t. tcp_rearm_rto will restart timer from now */
|
||||
inet_csk(sk)->icsk_pending = 0;
|
||||
rearm_timer:
|
||||
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
|
||||
inet_csk(sk)->icsk_rto,
|
||||
TCP_RTO_MAX);
|
||||
|
||||
if (likely(!err))
|
||||
NET_INC_STATS_BH(sock_net(sk),
|
||||
LINUX_MIB_TCPLOSSPROBES);
|
||||
tcp_rearm_rto(sk);
|
||||
}
|
||||
|
||||
/* Push out any pending frames which were held back due to
|
||||
|
@@ -1013,11 +1013,31 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
|
||||
if (!rt) {
|
||||
struct net *net = sock_net(sk);
|
||||
__u8 flow_flags = inet_sk_flowi_flags(sk);
|
||||
|
||||
fl4 = &fl4_stack;
|
||||
|
||||
/* unconnected socket. If output device is enslaved to a VRF
|
||||
* device lookup source address from VRF table. This mimics
|
||||
* behavior of ip_route_connect{_init}.
|
||||
*/
|
||||
if (netif_index_is_vrf(net, ipc.oif)) {
|
||||
flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos,
|
||||
RT_SCOPE_UNIVERSE, sk->sk_protocol,
|
||||
(flow_flags | FLOWI_FLAG_VRFSRC),
|
||||
faddr, saddr, dport,
|
||||
inet->inet_sport);
|
||||
|
||||
rt = ip_route_output_flow(net, fl4, sk);
|
||||
if (!IS_ERR(rt)) {
|
||||
saddr = fl4->saddr;
|
||||
ip_rt_put(rt);
|
||||
}
|
||||
}
|
||||
|
||||
flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos,
|
||||
RT_SCOPE_UNIVERSE, sk->sk_protocol,
|
||||
inet_sk_flowi_flags(sk),
|
||||
flow_flags,
|
||||
faddr, saddr, dport, inet->inet_sport);
|
||||
|
||||
security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
|
||||
@@ -1995,12 +2015,19 @@ void udp_v4_early_demux(struct sk_buff *skb)
|
||||
|
||||
skb->sk = sk;
|
||||
skb->destructor = sock_efree;
|
||||
dst = sk->sk_rx_dst;
|
||||
dst = READ_ONCE(sk->sk_rx_dst);
|
||||
|
||||
if (dst)
|
||||
dst = dst_check(dst, 0);
|
||||
if (dst)
|
||||
skb_dst_set_noref(skb, dst);
|
||||
if (dst) {
|
||||
/* DST_NOCACHE can not be used without taking a reference */
|
||||
if (dst->flags & DST_NOCACHE) {
|
||||
if (likely(atomic_inc_not_zero(&dst->__refcnt)))
|
||||
skb_dst_set(skb, dst);
|
||||
} else {
|
||||
skb_dst_set_noref(skb, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int udp_rcv(struct sk_buff *skb)
|
||||
|
@@ -19,7 +19,7 @@
|
||||
static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
|
||||
|
||||
static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
|
||||
int tos,
|
||||
int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
const xfrm_address_t *daddr)
|
||||
{
|
||||
@@ -28,6 +28,7 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
|
||||
memset(fl4, 0, sizeof(*fl4));
|
||||
fl4->daddr = daddr->a4;
|
||||
fl4->flowi4_tos = tos;
|
||||
fl4->flowi4_oif = oif;
|
||||
if (saddr)
|
||||
fl4->saddr = saddr->a4;
|
||||
|
||||
@@ -38,22 +39,22 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4,
|
||||
return ERR_CAST(rt);
|
||||
}
|
||||
|
||||
static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos,
|
||||
static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif,
|
||||
const xfrm_address_t *saddr,
|
||||
const xfrm_address_t *daddr)
|
||||
{
|
||||
struct flowi4 fl4;
|
||||
|
||||
return __xfrm4_dst_lookup(net, &fl4, tos, saddr, daddr);
|
||||
return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr);
|
||||
}
|
||||
|
||||
static int xfrm4_get_saddr(struct net *net,
|
||||
static int xfrm4_get_saddr(struct net *net, int oif,
|
||||
xfrm_address_t *saddr, xfrm_address_t *daddr)
|
||||
{
|
||||
struct dst_entry *dst;
|
||||
struct flowi4 fl4;
|
||||
|
||||
dst = __xfrm4_dst_lookup(net, &fl4, 0, NULL, daddr);
|
||||
dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr);
|
||||
if (IS_ERR(dst))
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
|
Reference in New Issue
Block a user