* [PATCH 5/7] ipv4: Make fib_select_default() not depend upon fib_result.
From: David Miller @ 2012-07-28 4:18 UTC (permalink / raw)
To: alexander.duyck; +Cc: eric.dumazet, netdev
Pass the arguments and return the result explicitly.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/ip_fib.h | 3 ++-
net/ipv4/fib_semantics.c | 19 +++++++++----------
net/ipv4/route.c | 2 +-
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 43be7230..8a57513 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -267,7 +267,8 @@ extern __be32 fib_compute_spec_dst(struct sk_buff *skb);
extern int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
u8 tos, int oif, struct net_device *dev,
struct in_device *idev, u32 *itag);
-extern void fib_select_default(struct fib_result *res);
+extern struct fib_nh *fib_select_default(struct fib_nh *nh, struct list_head *fa_head,
+ struct fib_table *tb);
#ifdef CONFIG_IP_ROUTE_CLASSID
static inline int fib_num_tclassid_users(struct net *net)
{
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index bf4c809..4c7b55c 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1134,11 +1134,10 @@ int fib_sync_down_dev(struct net_device *dev, int force)
}
/* Must be invoked inside of an RCU protected region. */
-void fib_select_default(struct fib_result *res)
+struct fib_nh *fib_select_default(struct fib_nh *res_nh, struct list_head *fa_head,
+ struct fib_table *tb)
{
struct fib_nh *nh = NULL, *last_resort = NULL;
- struct list_head *fa_head = res->fa_head;
- struct fib_table *tb = res->table;
int order = -1, last_idx = -1;
struct fib_alias *fa;
@@ -1146,12 +1145,12 @@ void fib_select_default(struct fib_result *res)
struct fib_nh *next_nh = &fa->fa_info->fib_nh[0];
if ((next_nh->nh_parent->fib_scope !=
- res->nh->nh_parent->fib_scope) ||
+ res_nh->nh_parent->fib_scope) ||
next_nh->nh_parent->fib_type != RTN_UNICAST)
continue;
if (next_nh->nh_parent->fib_priority >
- res->nh->nh_parent->fib_priority)
+ res_nh->nh_parent->fib_priority)
break;
if (!next_nh->nh_gw || next_nh->nh_scope != RT_SCOPE_LINK)
@@ -1160,11 +1159,11 @@ void fib_select_default(struct fib_result *res)
fib_alias_accessed(fa);
if (nh == NULL) {
- if (next_nh != res->nh)
+ if (next_nh != res_nh)
break;
} else if (!fib_detect_death(nh, order, &last_resort,
&last_idx, tb->tb_default)) {
- res->nh = nh;
+ res_nh = nh;
tb->tb_default = order;
goto out;
}
@@ -1179,16 +1178,16 @@ void fib_select_default(struct fib_result *res)
if (!fib_detect_death(nh, order, &last_resort, &last_idx,
tb->tb_default)) {
- res->nh = nh;
+ res_nh = nh;
tb->tb_default = order;
goto out;
}
if (last_idx >= 0)
- res->nh = last_resort;
+ res_nh = last_resort;
tb->tb_default = last_idx;
out:
- return;
+ return res_nh;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 597fbc0..9a247ff 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1970,7 +1970,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
if (!res.nh->nh_parent->fib_prefixlen &&
res.table->tb_num_default > 1 &&
type == RTN_UNICAST && !fl4->flowi4_oif)
- fib_select_default(&res);
+ res.nh = fib_select_default(res.nh, res.fa_head, res.table);
if (!fl4->saddr)
fl4->saddr = fib_res_prefsrc(net, &res);
--
1.7.10.4
^ permalink raw reply related
* [PATCH 6/7] ipv4: Make fib_select_multipath() not depend upon fib_result.
From: David Miller @ 2012-07-28 4:18 UTC (permalink / raw)
To: alexander.duyck; +Cc: eric.dumazet, netdev
Pass the arguments and return the result explicitly.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/ip_fib.h | 2 +-
net/ipv4/fib_semantics.c | 15 +++++++--------
net/ipv4/route.c | 4 ++--
3 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 8a57513..66f5365 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -287,7 +287,7 @@ extern int fib_sync_down_dev(struct net_device *dev, int force);
extern int fib_sync_down_addr(struct net *net, __be32 local);
extern void fib_update_nh_saddrs(struct net_device *dev);
extern int fib_sync_up(struct net_device *dev);
-extern void fib_select_multipath(struct fib_result *res);
+extern struct fib_nh *fib_select_multipath(struct fib_nh *res_nh);
/* Exported by fib_trie.c */
extern void fib_trie_init(void);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 4c7b55c..f83bef3 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1254,9 +1254,9 @@ int fib_sync_up(struct net_device *dev)
* The algorithm is suboptimal, but it provides really
* fair weighted route distribution.
*/
-void fib_select_multipath(struct fib_result *res)
+struct fib_nh *fib_select_multipath(struct fib_nh *res_nh)
{
- struct fib_info *fi = res->nh->nh_parent;
+ struct fib_info *fi = res_nh->nh_parent;
int w;
spin_lock_bh(&fib_multipath_lock);
@@ -1272,8 +1272,7 @@ void fib_select_multipath(struct fib_result *res)
if (power <= 0) {
spin_unlock_bh(&fib_multipath_lock);
/* Race condition: route has just become dead. */
- res->nh = &fi->fib_nh[0];
- return;
+ return &fi->fib_nh[0];
}
}
@@ -1291,15 +1290,15 @@ void fib_select_multipath(struct fib_result *res)
if (w <= 0) {
nexthop_nh->nh_power--;
fi->fib_power--;
- res->nh = &fi->fib_nh[nhsel];
spin_unlock_bh(&fib_multipath_lock);
- return;
+ return &fi->fib_nh[nhsel];
}
}
} endfor_nexthops(fi);
- /* Race condition: route has just become dead. */
- res->nh = &fi->fib_nh[0];
spin_unlock_bh(&fib_multipath_lock);
+
+ /* Race condition: route has just become dead. */
+ return &fi->fib_nh[0];
}
#endif
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 9a247ff..6b54323 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1461,7 +1461,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH
if (res->nh->nh_parent->fib_nhs > 1)
- fib_select_multipath(res);
+ res->nh = fib_select_multipath(res->nh);
#endif
/* create a routing cache entry */
@@ -1964,7 +1964,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
#ifdef CONFIG_IP_ROUTE_MULTIPATH
if (res.nh->nh_parent->fib_nhs > 1 && fl4->flowi4_oif == 0)
- fib_select_multipath(&res);
+ res.nh = fib_select_multipath(res.nh);
else
#endif
if (!res.nh->nh_parent->fib_prefixlen &&
--
1.7.10.4
^ permalink raw reply related
* [PATCH 7/7] ipv4: Perform multihop and default route resolution in check_leaf().
From: David Miller @ 2012-07-28 4:18 UTC (permalink / raw)
To: alexander.duyck; +Cc: eric.dumazet, netdev
And thus eliminate two more members of fib_result.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/ip_fib.h | 2 --
net/ipv4/fib_trie.c | 11 +++++++++--
net/ipv4/route.c | 17 -----------------
3 files changed, 9 insertions(+), 21 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 66f5365..400c1a7 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -128,8 +128,6 @@ struct fib_table;
struct fib_result {
u32 tclassid;
struct fib_nh *nh;
- struct fib_table *table;
- struct list_head *fa_head;
};
struct fib_result_nl {
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 3d1d450..afd5048 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1391,9 +1391,16 @@ static int check_leaf(struct fib_table *tb, struct trie *t, struct leaf *l,
#ifdef CONFIG_IP_FIB_TRIE_STATS
t->stats.semantic_match_passed++;
#endif
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (fi->fib_nhs > 1 && !flp->flowi4_oif)
+ nh = fib_select_multipath(nh);
+ else
+#endif
+ if (!li->plen && tb->tb_num_default > 1 &&
+ fi->fib_type == RTN_UNICAST &&
+ !flp->flowi4_oif)
+ nh = fib_select_default(nh, &li->falh, tb);
res->nh = nh;
- res->table = tb;
- res->fa_head = &li->falh;
if (!(fib_flags & FIB_LOOKUP_NOREF))
atomic_inc(&fi->fib_clntref);
return 0;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 6b54323..2d1ede9 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1459,11 +1459,6 @@ static int ip_mkroute_input(struct sk_buff *skb,
struct in_device *in_dev,
__be32 daddr, __be32 saddr, u32 tos)
{
-#ifdef CONFIG_IP_ROUTE_MULTIPATH
- if (res->nh->nh_parent->fib_nhs > 1)
- res->nh = fib_select_multipath(res->nh);
-#endif
-
/* create a routing cache entry */
return __mkroute_input(skb, res, in_dev, daddr, saddr, tos);
}
@@ -1814,7 +1809,6 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
res.tclassid = 0;
res.nh = NULL;
- res.table = NULL;
orig_oif = fl4->flowi4_oif;
@@ -1916,7 +1910,6 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
if (fib_lookup(net, fl4, &res)) {
res.nh = NULL;
- res.table = NULL;
if (fl4->flowi4_oif) {
/* Apparently, routing tables are wrong. Assume,
that the destination is on link.
@@ -1962,16 +1955,6 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
goto make_route;
}
-#ifdef CONFIG_IP_ROUTE_MULTIPATH
- if (res.nh->nh_parent->fib_nhs > 1 && fl4->flowi4_oif == 0)
- res.nh = fib_select_multipath(res.nh);
- else
-#endif
- if (!res.nh->nh_parent->fib_prefixlen &&
- res.table->tb_num_default > 1 &&
- type == RTN_UNICAST && !fl4->flowi4_oif)
- res.nh = fib_select_default(res.nh, res.fa_head, res.table);
-
if (!fl4->saddr)
fl4->saddr = fib_res_prefsrc(net, &res);
--
1.7.10.4
^ permalink raw reply related
* Re: more interrupts (lower performance) in bare-metal compared with running VM
From: Eric Dumazet @ 2012-07-28 4:32 UTC (permalink / raw)
To: sheng qiu; +Cc: kvm, linux-kernel, netdev
In-Reply-To: <CAB7xdi=DrE356=U1Jr1Z=ROo2X3XNM5uKcgiZJTKY+EdsTu7gw@mail.gmail.com>
On Fri, 2012-07-27 at 22:09 -0500, sheng qiu wrote:
> Hi all,
>
> i am comparing network throughput performance under bare-metal case
> with that running VM with assigned-device (assigned NIC). i have two
> physical machines (each has a 10Gbit NIC), one is used as remote
> server (run netserver) and the other is used as the target tested one
> (run netperf with different send message size, TCP_STREAM test). the
> remote NIC is connected directly with the tested NIC, both are 10Gbit.
> fore bare-metal case, i enable 1 cpu core, for VM i also configure 1
> vcpu (the memory is sufficient for both bare-metal and VM case). i
> run netperf for 120 seconds and got the following results:
>
> send message interrupts throughput (mbit/s)
> bare-metal 256 10696290 1114.84
> 512 10106786 1391.92
> 1024 10071032 1508.09
> 2048 4560857 3434.65
> 4096 3292200 4762.26
> 8192 3169801 4733.89
> 16384 2780529 4892.6
>
Are these interrupt counts taken on the receiver ?
> VM(assigned NIC) 256 3817904 2249.35
> 512 3599007 4342.81
> 1024 3005601 4134.69
> 2048 2952122 4484
> 4096 2682874 4566.34
> 8192 2786719 4734.39
> 16384 2603835 4540.47
>
> as shown, the interrupts for bare-metal case is much more than the VM
> case for some message size. we also see the throughput for those
> situations is lower than VM case. it's strange that the bare-metal has
> lower performance than the VM case. Does anyone have comments on this?
> i am very confused.
Well, I think you answered to your question. High interrupt rates
are not good for throughput. They might be good for latencies.
Using a VM adds delays and several frames might be delivered per
interrupt.
Using bare metal is faster and only one frame is delivered by NIC per
interrupt.
Try TCP_RR instead of TCP_STREAM for example.
What NIC is it exactly ? It seems it has no coalescing or LRO strategy.
ethtool -k eth0
ethtool -c eth0
What kernel version as used, because 4892 Mbits is not line rate.
^ permalink raw reply
* Re: [PATCH 00/16] Remove the ipv4 routing cache
From: Alexander Duyck @ 2012-07-28 5:45 UTC (permalink / raw)
To: David Miller; +Cc: eric.dumazet, netdev
In-Reply-To: <20120727.211528.1280331721532176100.davem@davemloft.net>
On Fri, Jul 27, 2012 at 9:15 PM, David Miller <davem@davemloft.net> wrote:
> From: David Miller <davem@davemloft.net>
> Date: Thu, 26 Jul 2012 23:02:46 -0700 (PDT)
>
>> Therefore one area of simplification would be to just return a pointer
>> to the FIB nexthop, rather than the fib_info pointer and the nexthop
>> index. We can get to the fib_info, if we need to, via the nh_parent
>> pointer of the nexthop.
>
> So I'm about to post an RFC set of patches which show this kind
> of simplification. It gets fib_result down to two members:
>
> u32 tclassid;
> struct fib_nh *nh;
>
> If I could get rid of that tclassid it would be really nice. But
> that's hard because the tclassid is fetched from the fib_rule and
> all of that lookup path is abstracted behind a common layer
> that's shared between ipv4 and ipv6 so it's a bit of work changing
> arg conventions.
>
> These changes help, but only ever so slightly, in my testing.
I probably won't be able to do any real testing for the patches until
Monday, or at least I may let somebody else test the patches first
just to make sure they don't panic the system before I do anything
with them.
Thanks,
Alex
^ permalink raw reply
* Re: [PATCH 0/7] Deconstruct struct fib_result
From: Alexander Duyck @ 2012-07-28 6:41 UTC (permalink / raw)
To: David Miller; +Cc: eric.dumazet, netdev
In-Reply-To: <20120727.211814.1628871775065221675.davem@davemloft.net>
On Fri, Jul 27, 2012 at 9:18 PM, David Miller <davem@davemloft.net> wrote:
>
> This patch set tries to move towards reducing struct fib_result down
> to it's absolute minimum.
>
> The eventual idea is to make it so that fib_lookup() simply
> returns a "struct fib_nh *" and pointer encoded errnos, instead
> of writing into a complicated structure as the return value on
> the stack as is done now.
>
> Signed-off-by: David S. Miller <davem@davemloft.net>
I was wondering why you couldn't wrap the tclassid value in result
with an #ifdef CONFIG_IP_ROUTE_CLASSID so that it is stripped if you
don't have that defined? I did a quick grep through the kernel and it
seems like there are only a few spots that are accessing it without
the define being checked and most of those are just setting it to 0.
Also is there any specific reason to be passing the trie pointer to
check_leaf? From what I can tell it looks like that it is just used
for updating the trie stats that are stripped if we want performance,
and the trie pointer should be retrievable via the fib table pointer
if we really wanted it anyway.
Thanks,
Alex
^ permalink raw reply
* Re: [PATCH 0/7] Deconstruct struct fib_result
From: David Miller @ 2012-07-28 6:55 UTC (permalink / raw)
To: alexander.duyck; +Cc: eric.dumazet, netdev
In-Reply-To: <CAKgT0UcuvFGJTCxMwVa+rEnQHaNg0V6EH4XpO29fXuFADSBpAQ@mail.gmail.com>
From: Alexander Duyck <alexander.duyck@gmail.com>
Date: Fri, 27 Jul 2012 23:41:50 -0700
> I was wondering why you couldn't wrap the tclassid value in result
> with an #ifdef CONFIG_IP_ROUTE_CLASSID so that it is stripped if you
> don't have that defined?
I am so over these feature ifdefs in the routing code, because
realistically everyone turns all the crap on. Therefore we have to be
optimal when it's all on.
^ permalink raw reply
* Re: [PATCH net-next] GRE over IPv6
From: Dmitry Kozlov @ 2012-07-28 7:17 UTC (permalink / raw)
To: David Miller; +Cc: netdev
>Why have you submitted these patches two times?
Sorry, that was a mistake...
^ permalink raw reply
* Re: [PATCH v2] ppp: add 64 bit stats
From: Eric Dumazet @ 2012-07-28 7:39 UTC (permalink / raw)
To: Kevin Groeneveld; +Cc: netdev
In-Reply-To: <1343446733-4791-1-git-send-email-kgroeneveld@gmail.com>
On Fri, 2012-07-27 at 23:38 -0400, Kevin Groeneveld wrote:
> Add 64 bit stats to ppp driver. The 64 bit stats include tx_bytes,
> rx_bytes, tx_packets and rx_packets. Other stats are still 32 bit.
> The 64 bit stats can be retrieved via the ndo_get_stats operation. The
> SIOCGPPPSTATS ioctl is still 32 bit stats only.
>
> Signed-off-by: Kevin Groeneveld <kgroeneveld@gmail.com>
> ---
> v2: - do not use percpu variables for stats
> - use ppp_recv_lock/ppp_xmit_lock when reading 64 bit stats
>
Seems fine to me this time ;)
Acked-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* [PATCH net-next v2] GRE over IPv6
From: Dmitry Kozlov @ 2012-07-28 7:35 UTC (permalink / raw)
To: netdev
GRE over IPv6 implementation.
Signed-off-by: Dmitry Kozlov <xeb@mail.ru>
---
Changes:
Initialize nt->dev before calling ip6gre_tnl_link_config in
ip6gre_newlink.
include/linux/if_arp.h | 1 +
include/linux/if_tunnel.h | 3 ++
include/linux/ip6_tunnel.h | 18 +++++++++
include/net/ip6_tunnel.h | 40 ++++++++++++++++++++-
include/net/ipv6.h | 1 +
net/ipv6/Kconfig | 16 ++++++++
net/ipv6/Makefile | 1 +
net/ipv6/ip6_tunnel.c | 86 +++++++++++++++++++++++++++++++------------
8 files changed, 141 insertions(+), 25 deletions(-)
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index f0e69c6..9adcc29 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -92,6 +92,7 @@
#define ARPHRD_PHONET 820 /* PhoNet media type */
#define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */
#define ARPHRD_CAIF 822 /* CAIF media type */
+#define ARPHRD_IP6GRE 823 /* GRE over IPv6 */
#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
#define ARPHRD_NONE 0xFFFE /* zero header length */
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 5efff60..8c5035a 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -75,6 +75,9 @@ enum {
IFLA_GRE_TTL,
IFLA_GRE_TOS,
IFLA_GRE_PMTUDISC,
+ IFLA_GRE_ENCAP_LIMIT,
+ IFLA_GRE_FLOWINFO,
+ IFLA_GRE_FLAGS,
__IFLA_GRE_MAX,
};
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
index bf22b03..1efe2e0 100644
--- a/include/linux/ip6_tunnel.h
+++ b/include/linux/ip6_tunnel.h
@@ -31,4 +31,22 @@ struct ip6_tnl_parm {
struct in6_addr raddr; /* remote tunnel end-point address */
};
+struct ip6_tnl_parm2 {
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface */
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __be32 flowinfo; /* traffic class and flowlabel for tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point address */
+ struct in6_addr raddr; /* remote tunnel end-point address */
+
+ __be16 i_flags;
+ __be16 o_flags;
+ __be32 i_key;
+ __be32 o_key;
+};
+
+
#endif
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index 358fb86..8400ba0 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -5,6 +5,8 @@
#include <linux/netdevice.h>
#include <linux/ip6_tunnel.h>
+#define IP6TUNNEL_ERR_TIMEO (30*HZ)
+
/* capable of sending packets */
#define IP6_TNL_F_CAP_XMIT 0x10000
/* capable of receiving packets */
@@ -13,14 +15,40 @@
#define IP6_TNL_F_CAP_PER_PACKET 0x40000
/* IPv6 tunnel */
+struct __ip6_tnl_parm
+{
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface */
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __be32 flowinfo; /* traffic class and flowlabel for tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point address */
+ struct in6_addr raddr; /* remote tunnel end-point address */
+
+ __be16 i_flags;
+ __be16 o_flags;
+ __be32 i_key;
+ __be32 o_key;
+};
struct ip6_tnl {
struct ip6_tnl __rcu *next; /* next tunnel in list */
struct net_device *dev; /* virtual device associated with tunnel */
- struct ip6_tnl_parm parms; /* tunnel configuration parameters */
+ struct __ip6_tnl_parm parms; /* tunnel configuration parameters */
struct flowi fl; /* flowi template for xmit */
struct dst_entry *dst_cache; /* cached dst */
u32 dst_cookie;
+
+ int err_count;
+ unsigned long err_time;
+
+ /* These fields used only by GRE */
+ __u32 i_seqno; /* The last seen seqno */
+ __u32 o_seqno; /* The last output seqno */
+ int hlen; /* Precalculated GRE header length */
+ int mlink;
};
/* Tunnel encapsulation limit destination sub-option */
@@ -31,4 +59,14 @@ struct ipv6_tlv_tnl_enc_lim {
__u8 encap_limit; /* tunnel encapsulation limit */
} __packed;
+struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t);
+void ip6_tnl_dst_reset(struct ip6_tnl *t);
+void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst);
+int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
+ const struct in6_addr *raddr);
+int ip6_tnl_xmit_ctl(struct ip6_tnl *t);
+__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 * raw);
+__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
+ const struct in6_addr *raddr);
+
#endif
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 01c34b3..6d01fb0 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -34,6 +34,7 @@
#define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */
#define NEXTHDR_ROUTING 43 /* Routing header. */
#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */
+#define NEXTHDR_GRE 47 /* GRE header. */
#define NEXTHDR_ESP 50 /* Encapsulating security payload. */
#define NEXTHDR_AUTH 51 /* Authentication header. */
#define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 5728695..4f7fe72 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -201,6 +201,22 @@ config IPV6_TUNNEL
If unsure, say N.
+config IPV6_GRE
+ tristate "IPv6: GRE tunnel"
+ select IPV6_TUNNEL
+ ---help---
+ Tunneling means encapsulating data of one protocol type within
+ another protocol and sending it over a channel that understands the
+ encapsulating protocol. This particular tunneling driver implements
+ GRE (Generic Routing Encapsulation) and at this time allows
+ encapsulating of IPv4 or IPv6 over existing IPv6 infrastructure.
+ This driver is useful if the other endpoint is a Cisco router: Cisco
+ likes GRE much better than the other Linux tunneling driver ("IP
+ tunneling" above). In addition, GRE allows multicast redistribution
+ through the tunnel.
+
+ Saying M here will produce a module called ip6_gre. If unsure, say N.
+
config IPV6_MULTIPLE_TABLES
bool "IPv6: Multiple Routing Tables"
depends on EXPERIMENTAL
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 686934a..b6d3f79 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/
obj-$(CONFIG_IPV6_SIT) += sit.o
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
+obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
obj-y += addrconf_core.o exthdrs_core.o
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 9a1d5fe..fc24522 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -126,7 +126,7 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
* Locking : hash tables are protected by RCU and RTNL
*/
-static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
+struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
{
struct dst_entry *dst = t->dst_cache;
@@ -139,20 +139,23 @@ static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
return dst;
}
+EXPORT_SYMBOL_GPL(ip6_tnl_dst_check);
-static inline void ip6_tnl_dst_reset(struct ip6_tnl *t)
+void ip6_tnl_dst_reset(struct ip6_tnl *t)
{
dst_release(t->dst_cache);
t->dst_cache = NULL;
}
+EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
-static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
+void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
{
struct rt6_info *rt = (struct rt6_info *) dst;
t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
dst_release(t->dst_cache);
t->dst_cache = dst;
}
+EXPORT_SYMBOL_GPL(ip6_tnl_dst_store);
/**
* ip6_tnl_lookup - fetch tunnel matching the end-point addresses
@@ -200,7 +203,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_
**/
static struct ip6_tnl __rcu **
-ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p)
+ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p)
{
const struct in6_addr *remote = &p->raddr;
const struct in6_addr *local = &p->laddr;
@@ -267,7 +270,7 @@ static void ip6_dev_free(struct net_device *dev)
* created tunnel or NULL
**/
-static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
+static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
{
struct net_device *dev;
struct ip6_tnl *t;
@@ -322,7 +325,7 @@ failed:
**/
static struct ip6_tnl *ip6_tnl_locate(struct net *net,
- struct ip6_tnl_parm *p, int create)
+ struct __ip6_tnl_parm *p, int create)
{
const struct in6_addr *remote = &p->raddr;
const struct in6_addr *local = &p->laddr;
@@ -374,8 +377,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)
* else index to encapsulation limit
**/
-static __u16
-parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
+__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 * raw)
{
const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
__u8 nexthdr = ipv6h->nexthdr;
@@ -425,6 +427,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
}
return 0;
}
+EXPORT_SYMBOL(ip6_tnl_parse_tlv_enc_lim);
/**
* ip6_tnl_err - tunnel error handler
@@ -480,7 +483,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
case ICMPV6_PARAMPROB:
teli = 0;
if ((*code) == ICMPV6_HDR_FIELD)
- teli = parse_tlv_tnl_enc_lim(skb, skb->data);
+ teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data);
if (teli && teli == *info - 2) {
tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
@@ -693,11 +696,11 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
IP6_ECN_set_ce(ipv6_hdr(skb));
}
-static __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
+__u32 ip6_tnl_get_cap(struct ip6_tnl *t,
const struct in6_addr *laddr,
const struct in6_addr *raddr)
{
- struct ip6_tnl_parm *p = &t->parms;
+ struct __ip6_tnl_parm *p = &t->parms;
int ltype = ipv6_addr_type(laddr);
int rtype = ipv6_addr_type(raddr);
__u32 flags = 0;
@@ -715,13 +718,14 @@ static __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
}
return flags;
}
+EXPORT_SYMBOL(ip6_tnl_get_cap);
/* called with rcu_read_lock() */
-static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
+int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
const struct in6_addr *laddr,
const struct in6_addr *raddr)
{
- struct ip6_tnl_parm *p = &t->parms;
+ struct __ip6_tnl_parm *p = &t->parms;
int ret = 0;
struct net *net = dev_net(t->dev);
@@ -740,6 +744,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
}
return ret;
}
+EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
/**
* ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
@@ -859,9 +864,9 @@ ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
}
-static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
+int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
{
- struct ip6_tnl_parm *p = &t->parms;
+ struct __ip6_tnl_parm *p = &t->parms;
int ret = 0;
struct net *net = dev_net(t->dev);
@@ -885,6 +890,8 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
}
return ret;
}
+EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
+
/**
* ip6_tnl_xmit2 - encapsulate packet and send
* @skb: the outgoing socket buffer
@@ -1085,7 +1092,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
!ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
return -1;
- offset = parse_tlv_tnl_enc_lim(skb, skb_network_header(skb));
+ offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
if (offset > 0) {
struct ipv6_tlv_tnl_enc_lim *tel;
tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
@@ -1152,7 +1159,7 @@ tx_err:
static void ip6_tnl_link_config(struct ip6_tnl *t)
{
struct net_device *dev = t->dev;
- struct ip6_tnl_parm *p = &t->parms;
+ struct __ip6_tnl_parm *p = &t->parms;
struct flowi6 *fl6 = &t->fl.u.ip6;
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
@@ -1215,7 +1222,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
**/
static int
-ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
+ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
{
t->parms.laddr = p->laddr;
t->parms.raddr = p->raddr;
@@ -1230,6 +1237,32 @@ ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
return 0;
}
+static void ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
+{
+ p->laddr = u->laddr;
+ p->raddr = u->raddr;
+ p->flags = u->flags;
+ p->hop_limit = u->hop_limit;
+ p->encap_limit = u->encap_limit;
+ p->flowinfo = u->flowinfo;
+ p->link = u->link;
+ p->proto = u->proto;
+ memcpy(p->name, u->name, sizeof(u->name));
+}
+
+static void ip6_tnl_parm_to_user(struct ip6_tnl_parm *u, const struct __ip6_tnl_parm *p)
+{
+ u->laddr = p->laddr;
+ u->raddr = p->raddr;
+ u->flags = p->flags;
+ u->hop_limit = p->hop_limit;
+ u->encap_limit = p->encap_limit;
+ u->flowinfo = p->flowinfo;
+ u->link = p->link;
+ u->proto = p->proto;
+ memcpy(u->name, p->name, sizeof(u->name));
+}
+
/**
* ip6_tnl_ioctl - configure ipv6 tunnels from userspace
* @dev: virtual device associated with tunnel
@@ -1263,6 +1296,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
int err = 0;
struct ip6_tnl_parm p;
+ struct __ip6_tnl_parm p1;
struct ip6_tnl *t = NULL;
struct net *net = dev_net(dev);
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
@@ -1274,11 +1308,12 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
err = -EFAULT;
break;
}
- t = ip6_tnl_locate(net, &p, 0);
+ ip6_tnl_parm_from_user(&p1, &p);
+ t = ip6_tnl_locate(net, &p1, 0);
}
if (t == NULL)
t = netdev_priv(dev);
- memcpy(&p, &t->parms, sizeof (p));
+ ip6_tnl_parm_to_user(&p, &t->parms);
if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
err = -EFAULT;
}
@@ -1295,7 +1330,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
p.proto != 0)
break;
- t = ip6_tnl_locate(net, &p, cmd == SIOCADDTUNNEL);
+ ip6_tnl_parm_from_user(&p1, &p);
+ t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
if (t != NULL) {
if (t->dev != dev) {
@@ -1307,13 +1343,14 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
ip6_tnl_unlink(ip6n, t);
synchronize_net();
- err = ip6_tnl_change(t, &p);
+ err = ip6_tnl_change(t, &p1);
ip6_tnl_link(ip6n, t);
netdev_state_change(dev);
}
if (t) {
err = 0;
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof (p)))
+ ip6_tnl_parm_to_user(&p, &t->parms);
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p)))
err = -EFAULT;
} else
@@ -1329,7 +1366,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
break;
err = -ENOENT;
- if ((t = ip6_tnl_locate(net, &p, 0)) == NULL)
+ ip6_tnl_parm_from_user(&p1, &p);
+ if ((t = ip6_tnl_locate(net, &p1, 0)) == NULL)
break;
err = -EPERM;
if (t->dev == ip6n->fb_tnl_dev)
^ permalink raw reply related
* [PATCH iproute2 v2] GRE over IPv6 tunnel support
From: Dmitry Kozlov @ 2012-07-28 7:38 UTC (permalink / raw)
To: netdev
GRE over IPv6 tunnel support.
Signed-off-by: Dmitry Kozlov <xeb@mail.ru>
---
Changes:
Implemented 'ip link' family of commands to manage
ip6gre/ip6gretap tunnels.
include/linux/if_arp.h | 15 ++
include/linux/if_tunnel.h | 21 +++
include/linux/ip6_tunnel.h | 18 ++
ip/Makefile | 2 +-
ip/ip6tunnel.c | 133 +++++++++++++--
ip/link_gre6.c | 397 ++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 567 insertions(+), 19 deletions(-)
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index d2de0f9..9adcc29 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -92,6 +92,7 @@
#define ARPHRD_PHONET 820 /* PhoNet media type */
#define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */
#define ARPHRD_CAIF 822 /* CAIF media type */
+#define ARPHRD_IP6GRE 823 /* GRE over IPv6 */
#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
#define ARPHRD_NONE 0xFFFE /* zero header length */
@@ -154,5 +155,19 @@ struct arphdr {
};
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct arphdr *arp_hdr(const struct sk_buff *skb)
+{
+ return (struct arphdr *)skb_network_header(skb);
+}
+
+static inline int arp_hdr_len(struct net_device *dev)
+{
+ /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
+ return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2;
+}
+#endif
#endif /* _LINUX_IF_ARP_H */
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 8c819b8..8c5035a 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -4,6 +4,10 @@
#include <linux/types.h>
#include <asm/byteorder.h>
+#ifdef __KERNEL__
+#include <linux/ip.h>
+#include <linux/in6.h>
+#endif
#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
@@ -71,9 +75,26 @@ enum {
IFLA_GRE_TTL,
IFLA_GRE_TOS,
IFLA_GRE_PMTUDISC,
+ IFLA_GRE_ENCAP_LIMIT,
+ IFLA_GRE_FLOWINFO,
+ IFLA_GRE_FLAGS,
__IFLA_GRE_MAX,
};
#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
+/* VTI-mode i_flags */
+#define VTI_ISVTI 0x0001
+
+enum {
+ IFLA_VTI_UNSPEC,
+ IFLA_VTI_LINK,
+ IFLA_VTI_IKEY,
+ IFLA_VTI_OKEY,
+ IFLA_VTI_LOCAL,
+ IFLA_VTI_REMOTE,
+ __IFLA_VTI_MAX,
+};
+
+#define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1)
#endif /* _IF_TUNNEL_H_ */
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
index bf22b03..1efe2e0 100644
--- a/include/linux/ip6_tunnel.h
+++ b/include/linux/ip6_tunnel.h
@@ -31,4 +31,22 @@ struct ip6_tnl_parm {
struct in6_addr raddr; /* remote tunnel end-point address */
};
+struct ip6_tnl_parm2 {
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface */
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __be32 flowinfo; /* traffic class and flowlabel for tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point address */
+ struct in6_addr raddr; /* remote tunnel end-point address */
+
+ __be16 i_flags;
+ __be16 o_flags;
+ __be32 i_key;
+ __be32 o_key;
+};
+
+
#endif
diff --git a/ip/Makefile b/ip/Makefile
index e029ea1..9c54a0b 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -3,7 +3,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o \
ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
iplink_vlan.o link_veth.o link_gre.o iplink_can.o \
- iplink_macvlan.o iplink_macvtap.o ipl2tp.o
+ iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_gre6.o
RTMONOBJ=rtmon.o
diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c
index c9720eb..399a579 100644
--- a/ip/ip6tunnel.c
+++ b/ip/ip6tunnel.c
@@ -48,11 +48,12 @@ static void usage(void) __attribute__((noreturn));
static void usage(void)
{
fprintf(stderr, "Usage: ip -f inet6 tunnel { add | change | del | show } [ NAME ]\n");
- fprintf(stderr, " [ mode { ip6ip6 | ipip6 | any } ]\n");
+ fprintf(stderr, " [ mode { ip6ip6 | ipip6 | ip6gre | any } ]\n");
fprintf(stderr, " [ remote ADDR local ADDR ] [ dev PHYS_DEV ]\n");
fprintf(stderr, " [ encaplimit ELIM ]\n");
fprintf(stderr ," [ hoplimit TTL ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
fprintf(stderr, " [ dscp inherit ]\n");
+ fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where: NAME := STRING\n");
fprintf(stderr, " ADDR := IPV6_ADDRESS\n");
@@ -60,12 +61,13 @@ static void usage(void)
IPV6_DEFAULT_TNL_ENCAP_LIMIT);
fprintf(stderr, " TTL := 0..255 (default=%d)\n",
DEFAULT_TNL_HOP_LIMIT);
- fprintf(stderr, " TOS := { 0x0..0xff | inherit }\n");
+ fprintf(stderr, " TCLASS := { 0x0..0xff | inherit }\n");
fprintf(stderr, " FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+ fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
exit(-1);
}
-static void print_tunnel(struct ip6_tnl_parm *p)
+static void print_tunnel(struct ip6_tnl_parm2 *p)
{
char remote[64];
char local[64];
@@ -104,9 +106,29 @@ static void print_tunnel(struct ip6_tnl_parm *p)
if (p->flags & IP6_TNL_F_RCV_DSCP_COPY)
printf(" dscp inherit");
+
+ if (p->proto == IPPROTO_GRE) {
+ if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) && p->o_key == p->i_key)
+ printf(" key %u", ntohl(p->i_key));
+ else if ((p->i_flags|p->o_flags)&GRE_KEY) {
+ if (p->i_flags&GRE_KEY)
+ printf(" ikey %u ", ntohl(p->i_key));
+ if (p->o_flags&GRE_KEY)
+ printf(" okey %u ", ntohl(p->o_key));
+ }
+
+ if (p->i_flags&GRE_SEQ)
+ printf("%s Drop packets out of sequence.\n", _SL_);
+ if (p->i_flags&GRE_CSUM)
+ printf("%s Checksum in received packet is required.", _SL_);
+ if (p->o_flags&GRE_SEQ)
+ printf("%s Sequence packets on output.", _SL_);
+ if (p->o_flags&GRE_CSUM)
+ printf("%s Checksum output packets.", _SL_);
+ }
}
-static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
+static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p)
{
int count = 0;
char medium[IFNAMSIZ];
@@ -124,6 +146,9 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
strcmp(*argv, "ipip6") == 0 ||
strcmp(*argv, "ip4ip6") == 0)
p->proto = IPPROTO_IPIP;
+ else if (strcmp(*argv, "ip6gre") == 0 ||
+ strcmp(*argv, "gre/ipv6") == 0)
+ p->proto = IPPROTO_GRE;
else if (strcmp(*argv, "any/ipv6") == 0 ||
strcmp(*argv, "any") == 0)
p->proto = 0;
@@ -199,6 +224,60 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
if (strcmp(*argv, "inherit") != 0)
invarg("not inherit", *argv);
p->flags |= IP6_TNL_F_RCV_DSCP_COPY;
+ } else if (strcmp(*argv, "key") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->i_flags |= GRE_KEY;
+ p->o_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->i_key = p->o_key = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"key\"\n");
+ exit(-1);
+ }
+ p->i_key = p->o_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "ikey") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->i_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->i_key = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"ikey\"\n");
+ exit(-1);
+ }
+ p->i_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "okey") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->o_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->o_key = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"okey\"\n");
+ exit(-1);
+ }
+ p->o_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "seq") == 0) {
+ p->i_flags |= GRE_SEQ;
+ p->o_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "iseq") == 0) {
+ p->i_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "oseq") == 0) {
+ p->o_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "csum") == 0) {
+ p->i_flags |= GRE_CSUM;
+ p->o_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "icsum") == 0) {
+ p->i_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "ocsum") == 0) {
+ p->o_flags |= GRE_CSUM;
} else {
if (strcmp(*argv, "name") == 0) {
NEXT_ARG();
@@ -209,7 +288,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
duparg2("name", *argv);
strncpy(p->name, *argv, IFNAMSIZ - 1);
if (cmd == SIOCCHGTUNNEL && count == 0) {
- struct ip6_tnl_parm old_p;
+ struct ip6_tnl_parm2 old_p;
memset(&old_p, 0, sizeof(old_p));
if (tnl_get_ioctl(*argv, &old_p))
return -1;
@@ -227,7 +306,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
return 0;
}
-static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
+static void ip6_tnl_parm_init(struct ip6_tnl_parm2 *p, int apply_default)
{
memset(p, 0, sizeof(*p));
p->proto = IPPROTO_IPV6;
@@ -241,8 +320,8 @@ static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
* @p1: user specified parameter
* @p2: database entry
*/
-static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
- const struct ip6_tnl_parm *p2)
+static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1,
+ const struct ip6_tnl_parm2 *p2)
{
return ((!p1->link || p1->link == p2->link) &&
(!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
@@ -260,7 +339,7 @@ static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
(!p1->flags || (p1->flags & p2->flags)));
}
-static int do_tunnels_list(struct ip6_tnl_parm *p)
+static int do_tunnels_list(struct ip6_tnl_parm2 *p)
{
char buf[512];
int err = -1;
@@ -284,7 +363,7 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
rx_fifo, rx_frame,
tx_bytes, tx_packets, tx_errs, tx_drops,
tx_fifo, tx_colls, tx_carrier, rx_multi;
- struct ip6_tnl_parm p1;
+ struct ip6_tnl_parm2 p1;
char *ptr;
buf[sizeof(buf) - 1] = '\0';
@@ -309,10 +388,12 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
fprintf(stderr, "Failed to get type of [%s]\n", name);
continue;
}
- if (type != ARPHRD_TUNNEL6)
+ if (type != ARPHRD_TUNNEL6 && type != ARPHRD_IP6GRE)
continue;
memset(&p1, 0, sizeof(p1));
ip6_tnl_parm_init(&p1, 0);
+ if (type == ARPHRD_IP6GRE)
+ p1.proto = IPPROTO_GRE;
strcpy(p1.name, name);
p1.link = ll_name_to_index(p1.name);
if (p1.link == 0)
@@ -343,7 +424,7 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
static int do_show(int argc, char **argv)
{
- struct ip6_tnl_parm p;
+ struct ip6_tnl_parm2 p;
ll_init_map(&rth);
ip6_tnl_parm_init(&p, 0);
@@ -366,28 +447,44 @@ static int do_show(int argc, char **argv)
static int do_add(int cmd, int argc, char **argv)
{
- struct ip6_tnl_parm p;
+ struct ip6_tnl_parm2 p;
ip6_tnl_parm_init(&p, 1);
if (parse_args(argc, argv, cmd, &p) < 0)
return -1;
- return tnl_add_ioctl(cmd,
- cmd == SIOCCHGTUNNEL && p.name[0] ?
- p.name : "ip6tnl0", p.name, &p);
+ switch (p.proto) {
+ case IPPROTO_IPIP:
+ case IPPROTO_IPV6:
+ return tnl_add_ioctl(cmd, "ip6tnl0", p.name, &p);
+ case IPPROTO_GRE:
+ return tnl_add_ioctl(cmd, "ip6gre0", p.name, &p);
+ default:
+ fprintf(stderr, "cannot determine tunnel mode (ip6ip6, ipip6 or gre)\n");
+ }
+ return -1;
}
static int do_del(int argc, char **argv)
{
- struct ip6_tnl_parm p;
+ struct ip6_tnl_parm2 p;
ip6_tnl_parm_init(&p, 1);
if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
return -1;
- return tnl_del_ioctl(p.name[0] ? p.name : "ip6tnl0", p.name, &p);
+ switch (p.proto) {
+ case IPPROTO_IPIP:
+ case IPPROTO_IPV6:
+ return tnl_del_ioctl("ip6tnl0", p.name, &p);
+ case IPPROTO_GRE:
+ return tnl_del_ioctl("ip6gre0", p.name, &p);
+ default:
+ return tnl_del_ioctl(p.name, p.name, &p);
+ }
+ return -1;
}
int do_ip6tunnel(int argc, char **argv)
diff --git a/ip/link_gre6.c b/ip/link_gre6.c
new file mode 100644
index 0000000..3ffd3ce
--- /dev/null
+++ b/ip/link_gre6.c
@@ -0,0 +1,397 @@
+/*
+ * link_gre.c gre driver module
+ *
+ * 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.
+ *
+ * Authors: Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+#include <linux/ip6_tunnel.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+#include "tunnel.h"
+
+#define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
+#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
+
+#define DEFAULT_TNL_HOP_LIMIT (64)
+
+static void usage(void) __attribute__((noreturn));
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
+ fprintf(stderr, " type { ip6gre | ip6gretap } [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+ fprintf(stderr, " [ hoplimit TTL ] [ encaplimit ELIM ]\n");
+ fprintf(stderr, " [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
+ fprintf(stderr, " [ dscp inherit ] [ dev PHYS_DEV ]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := IPV6_ADDRESS\n");
+ fprintf(stderr, " TTL := { 0..255 } (default=%d)\n",
+ DEFAULT_TNL_HOP_LIMIT);
+ fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
+ fprintf(stderr, " ELIM := { none | 0..255 }(default=%d)\n",
+ IPV6_DEFAULT_TNL_ENCAP_LIMIT);
+ fprintf(stderr, " FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+ exit(-1);
+}
+
+static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+ } req;
+ struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+ struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+ __u16 iflags = 0;
+ __u16 oflags = 0;
+ unsigned ikey = 0;
+ unsigned okey = 0;
+ struct in6_addr raddr = IN6ADDR_ANY_INIT;
+ struct in6_addr laddr = IN6ADDR_ANY_INIT;
+ unsigned link = 0;
+ unsigned flowinfo = 0;
+ unsigned flags = 0;
+ __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
+ __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+ int len;
+
+ if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETLINK;
+ req.i.ifi_family = preferred_family;
+ req.i.ifi_index = ifi->ifi_index;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+get_failed:
+ fprintf(stderr,
+ "Failed to get existing tunnel info.\n");
+ return -1;
+ }
+
+ len = req.n.nlmsg_len;
+ len -= NLMSG_LENGTH(sizeof(*ifi));
+ if (len < 0)
+ goto get_failed;
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
+
+ if (!tb[IFLA_LINKINFO])
+ goto get_failed;
+
+ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
+
+ if (!linkinfo[IFLA_INFO_DATA])
+ goto get_failed;
+
+ parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
+ linkinfo[IFLA_INFO_DATA]);
+
+ if (greinfo[IFLA_GRE_IKEY])
+ ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
+
+ if (greinfo[IFLA_GRE_OKEY])
+ okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
+
+ if (greinfo[IFLA_GRE_IFLAGS])
+ iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);
+
+ if (greinfo[IFLA_GRE_OFLAGS])
+ oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
+
+ if (greinfo[IFLA_GRE_LOCAL])
+ memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr));
+
+ if (greinfo[IFLA_GRE_REMOTE])
+ memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr));
+
+ if (greinfo[IFLA_GRE_TTL])
+ hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
+
+ if (greinfo[IFLA_GRE_LINK])
+ link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]);
+
+ if (greinfo[IFLA_GRE_ENCAP_LIMIT])
+ encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]);
+
+ if (greinfo[IFLA_GRE_FLOWINFO])
+ flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]);
+
+ if (greinfo[IFLA_GRE_FLAGS])
+ flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]);
+ }
+
+ while (argc > 0) {
+ if (!matches(*argv, "key")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ iflags |= GRE_KEY;
+ oflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0) < 0) {
+ fprintf(stderr,
+ "Invalid value for \"key\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+
+ ikey = okey = uval;
+ } else if (!matches(*argv, "ikey")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ iflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"ikey\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+ ikey = uval;
+ } else if (!matches(*argv, "okey")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ oflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value of \"okey\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+ okey = uval;
+ } else if (!matches(*argv, "seq")) {
+ iflags |= GRE_SEQ;
+ oflags |= GRE_SEQ;
+ } else if (!matches(*argv, "iseq")) {
+ iflags |= GRE_SEQ;
+ } else if (!matches(*argv, "oseq")) {
+ oflags |= GRE_SEQ;
+ } else if (!matches(*argv, "csum")) {
+ iflags |= GRE_CSUM;
+ oflags |= GRE_CSUM;
+ } else if (!matches(*argv, "icsum")) {
+ iflags |= GRE_CSUM;
+ } else if (!matches(*argv, "ocsum")) {
+ oflags |= GRE_CSUM;
+ } else if (!matches(*argv, "remote")) {
+ inet_prefix addr;
+ NEXT_ARG();
+ get_prefix(&addr, *argv, preferred_family);
+ if (addr.family == AF_UNSPEC)
+ invarg("\"remote\" address family is AF_UNSPEC", *argv);
+ memcpy(&raddr, &addr.data, sizeof(raddr));
+ } else if (!matches(*argv, "local")) {
+ inet_prefix addr;
+ NEXT_ARG();
+ get_prefix(&addr, *argv, preferred_family);
+ if (addr.family == AF_UNSPEC)
+ invarg("\"local\" address family is AF_UNSPEC", *argv);
+ memcpy(&laddr, &addr.data, sizeof(laddr));
+ } else if (!matches(*argv, "dev")) {
+ NEXT_ARG();
+ link = if_nametoindex(*argv);
+ if (link == 0)
+ exit(-1);
+ } else if (!matches(*argv, "ttl") ||
+ !matches(*argv, "hoplimit")) {
+ __u8 uval;
+ NEXT_ARG();
+ if (get_u8(&uval, *argv, 0))
+ invarg("invalid TTL", *argv);
+ hop_limit = uval;
+ } else if (!matches(*argv, "tos") ||
+ !matches(*argv, "tclass") ||
+ !matches(*argv, "dsfield")) {
+ __u8 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") == 0)
+ flags |= IP6_TNL_F_USE_ORIG_TCLASS;
+ else {
+ if (get_u8(&uval, *argv, 16))
+ invarg("invalid TClass", *argv);
+ flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
+ flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
+ }
+ } else if (strcmp(*argv, "flowlabel") == 0 ||
+ strcmp(*argv, "fl") == 0) {
+ __u32 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") == 0)
+ flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ else {
+ if (get_u32(&uval, *argv, 16))
+ invarg("invalid Flowlabel", *argv);
+ if (uval > 0xFFFFF)
+ invarg("invalid Flowlabel", *argv);
+ flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
+ flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ }
+ } else if (strcmp(*argv, "dscp") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0)
+ invarg("not inherit", *argv);
+ flags |= IP6_TNL_F_RCV_DSCP_COPY;
+ } else
+ usage();
+ argc--; argv++;
+ }
+
+ addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+ addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+ addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr));
+ addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr));
+ if (link)
+ addattr32(n, 1024, IFLA_GRE_LINK, link);
+ addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
+ addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
+ addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
+ addattr_l(n, 1024, IFLA_GRE_FLAGS, &flowinfo, 4);
+
+ return 0;
+}
+
+static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ char s1[1024];
+ char s2[64];
+ const char *local = "any";
+ const char *remote = "any";
+ unsigned iflags = 0;
+ unsigned oflags = 0;
+ unsigned flags = 0;
+ unsigned flowinfo = 0;
+ struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT;
+
+ if (!tb)
+ return;
+
+ if (tb[IFLA_GRE_FLAGS])
+ flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]);
+
+ if (tb[IFLA_GRE_FLOWINFO])
+ flags = rta_getattr_u32(tb[IFLA_GRE_FLOWINFO]);
+
+ if (tb[IFLA_GRE_REMOTE]) {
+ struct in6_addr addr;
+ memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr));
+
+ if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
+ remote = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1));
+ }
+
+ fprintf(f, "remote %s ", remote);
+
+ if (tb[IFLA_GRE_LOCAL]) {
+ struct in6_addr addr;
+ memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr));
+
+ if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
+ local = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1));
+ }
+
+ fprintf(f, "local %s ", local);
+
+ if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
+ unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
+ const char *n = if_indextoname(link, s2);
+
+ if (n)
+ fprintf(f, "dev %s ", n);
+ else
+ fprintf(f, "dev %u ", link);
+ }
+
+ if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
+ fprintf(f, "hoplimit %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
+
+ if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
+ fprintf(f, "encaplimit none ");
+ else if (tb[IFLA_GRE_ENCAP_LIMIT]) {
+ int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]);
+
+ fprintf(f, "encaplimit %d ", encap_limit);
+ }
+
+ if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
+ fprintf(f, "flowlabel inherit ");
+ else
+ fprintf(f, "flowlabel 0x%05x ", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
+
+ if (flags & IP6_TNL_F_RCV_DSCP_COPY)
+ fprintf(f, "dscp inherit ");
+
+ if (tb[IFLA_GRE_IFLAGS])
+ iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
+
+ if (tb[IFLA_GRE_OFLAGS])
+ oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
+
+ if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
+ inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
+ fprintf(f, "ikey %s ", s2);
+ }
+
+ if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
+ inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
+ fprintf(f, "okey %s ", s2);
+ }
+
+ if (iflags & GRE_SEQ)
+ fputs("iseq ", f);
+ if (oflags & GRE_SEQ)
+ fputs("oseq ", f);
+ if (iflags & GRE_CSUM)
+ fputs("icsum ", f);
+ if (oflags & GRE_CSUM)
+ fputs("ocsum ", f);
+}
+
+struct link_util ip6gre_link_util = {
+ .id = "ip6gre",
+ .maxattr = IFLA_GRE_MAX,
+ .parse_opt = gre_parse_opt,
+ .print_opt = gre_print_opt,
+};
+
+struct link_util ip6gretap_link_util = {
+ .id = "ip6gretap",
+ .maxattr = IFLA_GRE_MAX,
+ .parse_opt = gre_parse_opt,
+ .print_opt = gre_print_opt,
+};
^ permalink raw reply related
* [PATCH iproute2 v2] GRE over IPv6 tunnel support
From: Dmitry Kozlov @ 2012-07-28 7:52 UTC (permalink / raw)
To: netdev
GRE over IPv6 tunnel support.
Signed-off-by: Dmitry Kozlov <xeb@mail.ru>
---
Changes:
Implemented 'ip link' family of commands to manage
ip6gre/ip6gretap tunnels.
include/linux/if_arp.h | 15 ++
include/linux/if_tunnel.h | 21 +++
include/linux/ip6_tunnel.h | 18 ++
ip/Makefile | 2 +-
ip/ip6tunnel.c | 133 +++++++++++++--
ip/link_gre6.c | 397
++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 567
insertions(+), 19 deletions(-)
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index d2de0f9..9adcc29 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -92,6 +92,7 @@
#define ARPHRD_PHONET 820 /* PhoNet media
type */ #define ARPHRD_PHONET_PIPE
821 /* PhoNet pipe header */ #define
ARPHRD_CAIF 822 /* CAIF media
type */ +#define ARPHRD_IP6GRE
823 /* GRE over IPv6 */ #define
ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
#define ARPHRD_NONE 0xFFFE /* zero header length */ @@
-154,5 +155,19 @@ struct arphdr {
};
+#ifdef __KERNEL__
+#include <linux/skbuff.h>
+
+static inline struct arphdr *arp_hdr(const struct sk_buff *skb)
+{
+ return (struct arphdr *)skb_network_header(skb);
+}
+
+static inline int arp_hdr_len(struct net_device *dev)
+{
+ /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
+ return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) *
2; +}
+#endif
#endif /* _LINUX_IF_ARP_H */
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 8c819b8..8c5035a 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -4,6 +4,10 @@
#include <linux/types.h>
#include <asm/byteorder.h>
+#ifdef __KERNEL__
+#include <linux/ip.h>
+#include <linux/in6.h>
+#endif
#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0)
#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1)
@@ -71,9 +75,26 @@ enum {
IFLA_GRE_TTL,
IFLA_GRE_TOS,
IFLA_GRE_PMTUDISC,
+ IFLA_GRE_ENCAP_LIMIT,
+ IFLA_GRE_FLOWINFO,
+ IFLA_GRE_FLAGS,
__IFLA_GRE_MAX,
};
#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
+/* VTI-mode i_flags */
+#define VTI_ISVTI 0x0001
+
+enum {
+ IFLA_VTI_UNSPEC,
+ IFLA_VTI_LINK,
+ IFLA_VTI_IKEY,
+ IFLA_VTI_OKEY,
+ IFLA_VTI_LOCAL,
+ IFLA_VTI_REMOTE,
+ __IFLA_VTI_MAX,
+};
+
+#define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1)
#endif /* _IF_TUNNEL_H_ */
diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
index bf22b03..1efe2e0 100644
--- a/include/linux/ip6_tunnel.h
+++ b/include/linux/ip6_tunnel.h
@@ -31,4 +31,22 @@ struct ip6_tnl_parm {
struct in6_addr raddr; /* remote tunnel end-point
address */ };
+struct ip6_tnl_parm2 {
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface
*/
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __be32 flowinfo; /* traffic class and flowlabel for
tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point
address */
+ struct in6_addr raddr; /* remote tunnel end-point
address */ +
+ __be16 i_flags;
+ __be16 o_flags;
+ __be32 i_key;
+ __be32 o_key;
+};
+
+
#endif
diff --git a/ip/Makefile b/ip/Makefile
index e029ea1..9c54a0b 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -3,7 +3,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o
ipnetns.o \ ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o \
ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
iplink_vlan.o link_veth.o link_gre.o iplink_can.o \
- iplink_macvlan.o iplink_macvtap.o ipl2tp.o
+ iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_gre6.o
RTMONOBJ=rtmon.o
diff --git a/ip/ip6tunnel.c b/ip/ip6tunnel.c
index c9720eb..399a579 100644
--- a/ip/ip6tunnel.c
+++ b/ip/ip6tunnel.c
@@ -48,11 +48,12 @@ static void usage(void) __attribute__((noreturn));
static void usage(void)
{
fprintf(stderr, "Usage: ip -f inet6 tunnel { add | change |
del | show } [ NAME ]\n");
- fprintf(stderr, " [ mode { ip6ip6 | ipip6 | any }
]\n");
+ fprintf(stderr, " [ mode { ip6ip6 | ipip6 | ip6gre |
any } ]\n"); fprintf(stderr, " [ remote ADDR local ADDR ]
[ dev PHYS_DEV ]\n"); fprintf(stderr, " [ encaplimit ELIM
]\n"); fprintf(stderr ," [ hoplimit TTL ] [ tclass TCLASS ]
[ flowlabel FLOWLABEL ]\n"); fprintf(stderr, " [ dscp inherit
]\n");
+ fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ]
[ [i|o]csum ]\n"); fprintf(stderr, "\n");
fprintf(stderr, "Where: NAME := STRING\n");
fprintf(stderr, " ADDR := IPV6_ADDRESS\n");
@@ -60,12 +61,13 @@ static void usage(void)
IPV6_DEFAULT_TNL_ENCAP_LIMIT);
fprintf(stderr, " TTL := 0..255 (default=%d)\n",
DEFAULT_TNL_HOP_LIMIT);
- fprintf(stderr, " TOS := { 0x0..0xff |
inherit }\n");
+ fprintf(stderr, " TCLASS := { 0x0..0xff |
inherit }\n"); fprintf(stderr, " FLOWLABEL := { 0x0..0xfffff |
inherit }\n");
+ fprintf(stderr, " KEY := { DOTTED_QUAD |
NUMBER }\n"); exit(-1);
}
-static void print_tunnel(struct ip6_tnl_parm *p)
+static void print_tunnel(struct ip6_tnl_parm2 *p)
{
char remote[64];
char local[64];
@@ -104,9 +106,29 @@ static void print_tunnel(struct ip6_tnl_parm *p)
if (p->flags & IP6_TNL_F_RCV_DSCP_COPY)
printf(" dscp inherit");
+
+ if (p->proto == IPPROTO_GRE) {
+ if ((p->i_flags&GRE_KEY) && (p->o_flags&GRE_KEY) &&
p->o_key == p->i_key)
+ printf(" key %u", ntohl(p->i_key));
+ else if ((p->i_flags|p->o_flags)&GRE_KEY) {
+ if (p->i_flags&GRE_KEY)
+ printf(" ikey %u ", ntohl(p->i_key));
+ if (p->o_flags&GRE_KEY)
+ printf(" okey %u ", ntohl(p->o_key));
+ }
+
+ if (p->i_flags&GRE_SEQ)
+ printf("%s Drop packets out of sequence.\n",
_SL_);
+ if (p->i_flags&GRE_CSUM)
+ printf("%s Checksum in received packet is
required.", _SL_);
+ if (p->o_flags&GRE_SEQ)
+ printf("%s Sequence packets on output.",
_SL_);
+ if (p->o_flags&GRE_CSUM)
+ printf("%s Checksum output packets.", _SL_);
+ }
}
-static int parse_args(int argc, char **argv, int cmd, struct
ip6_tnl_parm *p) +static int parse_args(int argc, char **argv, int
cmd, struct ip6_tnl_parm2 *p) {
int count = 0;
char medium[IFNAMSIZ];
@@ -124,6 +146,9 @@ static int parse_args(int argc, char **argv, int
cmd, struct ip6_tnl_parm *p) strcmp(*argv, "ipip6") == 0 ||
strcmp(*argv, "ip4ip6") == 0)
p->proto = IPPROTO_IPIP;
+ else if (strcmp(*argv, "ip6gre") == 0 ||
+ strcmp(*argv, "gre/ipv6") == 0)
+ p->proto = IPPROTO_GRE;
else if (strcmp(*argv, "any/ipv6") == 0 ||
strcmp(*argv, "any") == 0)
p->proto = 0;
@@ -199,6 +224,60 @@ static int parse_args(int argc, char **argv, int
cmd, struct ip6_tnl_parm *p) if (strcmp(*argv, "inherit") != 0)
invarg("not inherit", *argv);
p->flags |= IP6_TNL_F_RCV_DSCP_COPY;
+ } else if (strcmp(*argv, "key") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->i_flags |= GRE_KEY;
+ p->o_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->i_key = p->o_key =
get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value
of \"key\"\n");
+ exit(-1);
+ }
+ p->i_key = p->o_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "ikey") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->i_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->i_key = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value
of \"ikey\"\n");
+ exit(-1);
+ }
+ p->i_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "okey") == 0) {
+ unsigned uval;
+ NEXT_ARG();
+ p->o_flags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ p->o_key = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value
of \"okey\"\n");
+ exit(-1);
+ }
+ p->o_key = htonl(uval);
+ }
+ } else if (strcmp(*argv, "seq") == 0) {
+ p->i_flags |= GRE_SEQ;
+ p->o_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "iseq") == 0) {
+ p->i_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "oseq") == 0) {
+ p->o_flags |= GRE_SEQ;
+ } else if (strcmp(*argv, "csum") == 0) {
+ p->i_flags |= GRE_CSUM;
+ p->o_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "icsum") == 0) {
+ p->i_flags |= GRE_CSUM;
+ } else if (strcmp(*argv, "ocsum") == 0) {
+ p->o_flags |= GRE_CSUM;
} else {
if (strcmp(*argv, "name") == 0) {
NEXT_ARG();
@@ -209,7 +288,7 @@ static int parse_args(int argc, char **argv, int
cmd, struct ip6_tnl_parm *p) duparg2("name", *argv);
strncpy(p->name, *argv, IFNAMSIZ - 1);
if (cmd == SIOCCHGTUNNEL && count == 0) {
- struct ip6_tnl_parm old_p;
+ struct ip6_tnl_parm2 old_p;
memset(&old_p, 0, sizeof(old_p));
if (tnl_get_ioctl(*argv, &old_p))
return -1;
@@ -227,7 +306,7 @@ static int parse_args(int argc, char **argv, int
cmd, struct ip6_tnl_parm *p) return 0;
}
-static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int
apply_default) +static void ip6_tnl_parm_init(struct ip6_tnl_parm2 *p,
int apply_default) {
memset(p, 0, sizeof(*p));
p->proto = IPPROTO_IPV6;
@@ -241,8 +320,8 @@ static void ip6_tnl_parm_init(struct ip6_tnl_parm
*p, int apply_default)
* @p1: user specified parameter
* @p2: database entry
*/
-static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
- const struct ip6_tnl_parm *p2)
+static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1,
+ const struct ip6_tnl_parm2 *p2)
{
return ((!p1->link || p1->link == p2->link) &&
(!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
@@ -260,7 +339,7 @@ static int ip6_tnl_parm_match(const struct
ip6_tnl_parm *p1, (!p1->flags || (p1->flags & p2->flags)));
}
-static int do_tunnels_list(struct ip6_tnl_parm *p)
+static int do_tunnels_list(struct ip6_tnl_parm2 *p)
{
char buf[512];
int err = -1;
@@ -284,7 +363,7 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
rx_fifo, rx_frame,
tx_bytes, tx_packets, tx_errs, tx_drops,
tx_fifo, tx_colls, tx_carrier, rx_multi;
- struct ip6_tnl_parm p1;
+ struct ip6_tnl_parm2 p1;
char *ptr;
buf[sizeof(buf) - 1] = '\0';
@@ -309,10 +388,12 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
fprintf(stderr, "Failed to get type of
[%s]\n", name); continue;
}
- if (type != ARPHRD_TUNNEL6)
+ if (type != ARPHRD_TUNNEL6 && type != ARPHRD_IP6GRE)
continue;
memset(&p1, 0, sizeof(p1));
ip6_tnl_parm_init(&p1, 0);
+ if (type == ARPHRD_IP6GRE)
+ p1.proto = IPPROTO_GRE;
strcpy(p1.name, name);
p1.link = ll_name_to_index(p1.name);
if (p1.link == 0)
@@ -343,7 +424,7 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
static int do_show(int argc, char **argv)
{
- struct ip6_tnl_parm p;
+ struct ip6_tnl_parm2 p;
ll_init_map(&rth);
ip6_tnl_parm_init(&p, 0);
@@ -366,28 +447,44 @@ static int do_show(int argc, char **argv)
static int do_add(int cmd, int argc, char **argv)
{
- struct ip6_tnl_parm p;
+ struct ip6_tnl_parm2 p;
ip6_tnl_parm_init(&p, 1);
if (parse_args(argc, argv, cmd, &p) < 0)
return -1;
- return tnl_add_ioctl(cmd,
- cmd == SIOCCHGTUNNEL && p.name[0] ?
- p.name : "ip6tnl0", p.name, &p);
+ switch (p.proto) {
+ case IPPROTO_IPIP:
+ case IPPROTO_IPV6:
+ return tnl_add_ioctl(cmd, "ip6tnl0", p.name, &p);
+ case IPPROTO_GRE:
+ return tnl_add_ioctl(cmd, "ip6gre0", p.name, &p);
+ default:
+ fprintf(stderr, "cannot determine tunnel mode (ip6ip6,
ipip6 or gre)\n");
+ }
+ return -1;
}
static int do_del(int argc, char **argv)
{
- struct ip6_tnl_parm p;
+ struct ip6_tnl_parm2 p;
ip6_tnl_parm_init(&p, 1);
if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
return -1;
- return tnl_del_ioctl(p.name[0] ? p.name : "ip6tnl0", p.name,
&p);
+ switch (p.proto) {
+ case IPPROTO_IPIP:
+ case IPPROTO_IPV6:
+ return tnl_del_ioctl("ip6tnl0", p.name, &p);
+ case IPPROTO_GRE:
+ return tnl_del_ioctl("ip6gre0", p.name, &p);
+ default:
+ return tnl_del_ioctl(p.name, p.name, &p);
+ }
+ return -1;
}
int do_ip6tunnel(int argc, char **argv)
diff --git a/ip/link_gre6.c b/ip/link_gre6.c
new file mode 100644
index 0000000..3ffd3ce
--- /dev/null
+++ b/ip/link_gre6.c
@@ -0,0 +1,397 @@
+/*
+ * link_gre.c gre driver module
+ *
+ * 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.
+ *
+ * Authors: Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <string.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+#include <linux/ip6_tunnel.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+#include "tunnel.h"
+
+#define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
+#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
+
+#define DEFAULT_TNL_HOP_LIMIT (64)
+
+static void usage(void) __attribute__((noreturn));
+static void usage(void)
+{
+ fprintf(stderr, "Usage: ip link { add | set | change | replace
| del } NAME\n");
+ fprintf(stderr, " type { ip6gre | ip6gretap }
[ remote ADDR ] [ local ADDR ]\n");
+ fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ]
[ [i|o]csum ]\n");
+ fprintf(stderr, " [ hoplimit TTL ] [ encaplimit ELIM
]\n");
+ fprintf(stderr, " [ tclass TCLASS ] [ flowlabel
FLOWLABEL ]\n");
+ fprintf(stderr, " [ dscp inherit ] [ dev PHYS_DEV
]\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Where: NAME := STRING\n");
+ fprintf(stderr, " ADDR := IPV6_ADDRESS\n");
+ fprintf(stderr, " TTL := { 0..255 }
(default=%d)\n",
+ DEFAULT_TNL_HOP_LIMIT);
+ fprintf(stderr, " KEY := { DOTTED_QUAD |
NUMBER }\n");
+ fprintf(stderr, " ELIM := { none |
0..255 }(default=%d)\n",
+ IPV6_DEFAULT_TNL_ENCAP_LIMIT);
+ fprintf(stderr, " FLOWLABEL := { 0x0..0xfffff |
inherit }\n");
+ exit(-1);
+}
+
+static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+ } req;
+ struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+ struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+ __u16 iflags = 0;
+ __u16 oflags = 0;
+ unsigned ikey = 0;
+ unsigned okey = 0;
+ struct in6_addr raddr = IN6ADDR_ANY_INIT;
+ struct in6_addr laddr = IN6ADDR_ANY_INIT;
+ unsigned link = 0;
+ unsigned flowinfo = 0;
+ unsigned flags = 0;
+ __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
+ __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+ int len;
+
+ if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETLINK;
+ req.i.ifi_family = preferred_family;
+ req.i.ifi_index = ifi->ifi_index;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
+get_failed:
+ fprintf(stderr,
+ "Failed to get existing tunnel
info.\n");
+ return -1;
+ }
+
+ len = req.n.nlmsg_len;
+ len -= NLMSG_LENGTH(sizeof(*ifi));
+ if (len < 0)
+ goto get_failed;
+
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
+
+ if (!tb[IFLA_LINKINFO])
+ goto get_failed;
+
+ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX,
tb[IFLA_LINKINFO]); +
+ if (!linkinfo[IFLA_INFO_DATA])
+ goto get_failed;
+
+ parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
+ linkinfo[IFLA_INFO_DATA]);
+
+ if (greinfo[IFLA_GRE_IKEY])
+ ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
+
+ if (greinfo[IFLA_GRE_OKEY])
+ okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
+
+ if (greinfo[IFLA_GRE_IFLAGS])
+ iflags =
rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]); +
+ if (greinfo[IFLA_GRE_OFLAGS])
+ oflags =
rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); +
+ if (greinfo[IFLA_GRE_LOCAL])
+ memcpy(&laddr,
RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr)); +
+ if (greinfo[IFLA_GRE_REMOTE])
+ memcpy(&raddr,
RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr)); +
+ if (greinfo[IFLA_GRE_TTL])
+ hop_limit =
rta_getattr_u8(greinfo[IFLA_GRE_TTL]); +
+ if (greinfo[IFLA_GRE_LINK])
+ link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]);
+
+ if (greinfo[IFLA_GRE_ENCAP_LIMIT])
+ encap_limit =
rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]);
+
+ if (greinfo[IFLA_GRE_FLOWINFO])
+ flowinfo =
rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]);
+
+ if (greinfo[IFLA_GRE_FLAGS])
+ flags =
rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]);
+ }
+
+ while (argc > 0) {
+ if (!matches(*argv, "key")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ iflags |= GRE_KEY;
+ oflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0) < 0)
{
+ fprintf(stderr,
+ "Invalid value for
\"key\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+
+ ikey = okey = uval;
+ } else if (!matches(*argv, "ikey")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ iflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value
of \"ikey\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+ ikey = uval;
+ } else if (!matches(*argv, "okey")) {
+ unsigned uval;
+
+ NEXT_ARG();
+ oflags |= GRE_KEY;
+ if (strchr(*argv, '.'))
+ uval = get_addr32(*argv);
+ else {
+ if (get_unsigned(&uval, *argv, 0)<0) {
+ fprintf(stderr, "invalid value
of \"okey\"\n");
+ exit(-1);
+ }
+ uval = htonl(uval);
+ }
+ okey = uval;
+ } else if (!matches(*argv, "seq")) {
+ iflags |= GRE_SEQ;
+ oflags |= GRE_SEQ;
+ } else if (!matches(*argv, "iseq")) {
+ iflags |= GRE_SEQ;
+ } else if (!matches(*argv, "oseq")) {
+ oflags |= GRE_SEQ;
+ } else if (!matches(*argv, "csum")) {
+ iflags |= GRE_CSUM;
+ oflags |= GRE_CSUM;
+ } else if (!matches(*argv, "icsum")) {
+ iflags |= GRE_CSUM;
+ } else if (!matches(*argv, "ocsum")) {
+ oflags |= GRE_CSUM;
+ } else if (!matches(*argv, "remote")) {
+ inet_prefix addr;
+ NEXT_ARG();
+ get_prefix(&addr, *argv, preferred_family);
+ if (addr.family == AF_UNSPEC)
+ invarg("\"remote\" address family is
AF_UNSPEC", *argv);
+ memcpy(&raddr, &addr.data, sizeof(raddr));
+ } else if (!matches(*argv, "local")) {
+ inet_prefix addr;
+ NEXT_ARG();
+ get_prefix(&addr, *argv, preferred_family);
+ if (addr.family == AF_UNSPEC)
+ invarg("\"local\" address family is
AF_UNSPEC", *argv);
+ memcpy(&laddr, &addr.data, sizeof(laddr));
+ } else if (!matches(*argv, "dev")) {
+ NEXT_ARG();
+ link = if_nametoindex(*argv);
+ if (link == 0)
+ exit(-1);
+ } else if (!matches(*argv, "ttl") ||
+ !matches(*argv, "hoplimit")) {
+ __u8 uval;
+ NEXT_ARG();
+ if (get_u8(&uval, *argv, 0))
+ invarg("invalid TTL", *argv);
+ hop_limit = uval;
+ } else if (!matches(*argv, "tos") ||
+ !matches(*argv, "tclass") ||
+ !matches(*argv, "dsfield")) {
+ __u8 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") == 0)
+ flags |= IP6_TNL_F_USE_ORIG_TCLASS;
+ else {
+ if (get_u8(&uval, *argv, 16))
+ invarg("invalid TClass",
*argv);
+ flowinfo |= htonl((__u32)uval << 20) &
IP6_FLOWINFO_TCLASS;
+ flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
+ }
+ } else if (strcmp(*argv, "flowlabel") == 0 ||
+ strcmp(*argv, "fl") == 0) {
+ __u32 uval;
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") == 0)
+ flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ else {
+ if (get_u32(&uval, *argv, 16))
+ invarg("invalid Flowlabel",
*argv);
+ if (uval > 0xFFFFF)
+ invarg("invalid Flowlabel",
*argv);
+ flowinfo |= htonl(uval) &
IP6_FLOWINFO_FLOWLABEL;
+ flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
+ }
+ } else if (strcmp(*argv, "dscp") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "inherit") != 0)
+ invarg("not inherit", *argv);
+ flags |= IP6_TNL_F_RCV_DSCP_COPY;
+ } else
+ usage();
+ argc--; argv++;
+ }
+
+ addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+ addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+ addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+ addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr));
+ addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr));
+ if (link)
+ addattr32(n, 1024, IFLA_GRE_LINK, link);
+ addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
+ addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
+ addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
+ addattr_l(n, 1024, IFLA_GRE_FLAGS, &flowinfo, 4);
+
+ return 0;
+}
+
+static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr
*tb[]) +{
+ char s1[1024];
+ char s2[64];
+ const char *local = "any";
+ const char *remote = "any";
+ unsigned iflags = 0;
+ unsigned oflags = 0;
+ unsigned flags = 0;
+ unsigned flowinfo = 0;
+ struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT;
+
+ if (!tb)
+ return;
+
+ if (tb[IFLA_GRE_FLAGS])
+ flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]);
+
+ if (tb[IFLA_GRE_FLOWINFO])
+ flags = rta_getattr_u32(tb[IFLA_GRE_FLOWINFO]);
+
+ if (tb[IFLA_GRE_REMOTE]) {
+ struct in6_addr addr;
+ memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]),
sizeof(addr)); +
+ if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
+ remote = format_host(AF_INET6, sizeof(addr),
&addr, s1, sizeof(s1));
+ }
+
+ fprintf(f, "remote %s ", remote);
+
+ if (tb[IFLA_GRE_LOCAL]) {
+ struct in6_addr addr;
+ memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]),
sizeof(addr)); +
+ if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
+ local = format_host(AF_INET6, sizeof(addr),
&addr, s1, sizeof(s1));
+ }
+
+ fprintf(f, "local %s ", local);
+
+ if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
+ unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
+ const char *n = if_indextoname(link, s2);
+
+ if (n)
+ fprintf(f, "dev %s ", n);
+ else
+ fprintf(f, "dev %u ", link);
+ }
+
+ if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
+ fprintf(f, "hoplimit %d ",
rta_getattr_u8(tb[IFLA_GRE_TTL])); +
+ if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
+ fprintf(f, "encaplimit none ");
+ else if (tb[IFLA_GRE_ENCAP_LIMIT]) {
+ int encap_limit =
rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]); +
+ fprintf(f, "encaplimit %d ", encap_limit);
+ }
+
+ if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
+ fprintf(f, "flowlabel inherit ");
+ else
+ fprintf(f, "flowlabel 0x%05x ", ntohl(flowinfo &
IP6_FLOWINFO_FLOWLABEL));
+
+ if (flags & IP6_TNL_F_RCV_DSCP_COPY)
+ fprintf(f, "dscp inherit ");
+
+ if (tb[IFLA_GRE_IFLAGS])
+ iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
+
+ if (tb[IFLA_GRE_OFLAGS])
+ oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
+
+ if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
+ inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2,
sizeof(s2));
+ fprintf(f, "ikey %s ", s2);
+ }
+
+ if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
+ inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2,
sizeof(s2));
+ fprintf(f, "okey %s ", s2);
+ }
+
+ if (iflags & GRE_SEQ)
+ fputs("iseq ", f);
+ if (oflags & GRE_SEQ)
+ fputs("oseq ", f);
+ if (iflags & GRE_CSUM)
+ fputs("icsum ", f);
+ if (oflags & GRE_CSUM)
+ fputs("ocsum ", f);
+}
+
+struct link_util ip6gre_link_util = {
+ .id = "ip6gre",
+ .maxattr = IFLA_GRE_MAX,
+ .parse_opt = gre_parse_opt,
+ .print_opt = gre_print_opt,
+};
+
+struct link_util ip6gretap_link_util = {
+ .id = "ip6gretap",
+ .maxattr = IFLA_GRE_MAX,
+ .parse_opt = gre_parse_opt,
+ .print_opt = gre_print_opt,
+};
^ permalink raw reply related
* [GIT] Networking
From: David Miller @ 2012-07-28 7:52 UTC (permalink / raw)
To: torvalds; +Cc: akpm, netdev, linux-kernel
Several bug fixes, some to new features appearing in this merge window,
some that have been around for a while.
I have a short list of known problems that need to be sorted out, but
all of them can be solved easily during the run up to 3.6-final.
I'll be offline until Sunday afternoon, but nothing need hold up
3.6-rc1 and the close of the merge window, networking wise, at this
point.
1) Fix interface check in ipv4 TCP early demux, from Eric Dumazet.
2) Fix a long standing bug in TCP DMA to userspace offload that can
hang applications using MSG_TRUNC, from Jiri Kosina.
3) Don't allow TCP_USER_TIMEOUT to be negative, from Hangbin Liu.
4) Don't use GFP_KERNEL under spinlock in kaweth driver, from Dan
Carpenter
Please pull, thanks a lot.
The following changes since commit b387e41e523c1aa347cff055455d0dd129357df4:
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc (2012-07-27 08:35:26 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git master
for you to fetch changes up to 7b9b04fb728ec0b94464ed902f3395aa592c5bcf:
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless (2012-07-27 14:25:40 -0700)
----------------------------------------------------------------
Dan Carpenter (1):
USB: kaweth.c: use GFP_ATOMIC under spin_lock
David S. Miller (1):
Merge branch 'for-davem' of git://git.kernel.org/.../linville/wireless
Eric Dumazet (1):
ipv4: fix TCP early demux
Hangbin Liu (1):
tcp: Add TCP_USER_TIMEOUT negative value check
Hauke Mehrtens (2):
bcma: fix regression in interrupt assignment on mips
bcma: add missing iounmap on error path
Jesse Gross (1):
Revert "openvswitch: potential NULL deref in sample()"
Jiri Benc (1):
net: fix rtnetlink IFF_PROMISC and IFF_ALLMULTI handling
Jiri Kosina (1):
tcp: perform DMA to userspace only if there is a task waiting for it
John W. Linville (1):
Merge branch 'master' of git://git.kernel.org/.../linville/wireless into for-davem
Thomas Huehn (1):
mac80211_hwsim: fix possible race condition in usage of info->control.sta & control.vif
drivers/bcma/driver_mips.c | 6 +++---
drivers/bcma/scan.c | 15 ++++++++++-----
drivers/net/usb/kaweth.c | 2 +-
drivers/net/wireless/mac80211_hwsim.c | 5 -----
net/core/rtnetlink.c | 8 +++++++-
net/ipv4/tcp.c | 5 ++++-
net/ipv4/tcp_input.c | 5 ++++-
net/ipv4/tcp_ipv4.c | 14 ++++++--------
net/ipv4/tcp_minisocks.c | 1 +
net/openvswitch/actions.c | 3 ---
10 files changed, 36 insertions(+), 28 deletions(-)
^ permalink raw reply
* [PATCH v2] dynamic_debug: Restore dev_dbg functionality, optimize stack
From: Joe Perches @ 2012-07-28 7:55 UTC (permalink / raw)
To: Andrew Morton, Greg Kroah-Hartman, David S. Miller, Jason Baron
Cc: Jim Cromie, Kay Sievers, linux-kernel, netdev
In-Reply-To: <1343334310.17538.32.camel@joe2Laptop>
commit c4e00daaa9 ("driver-core: extend dev_printk() to pass structured data")
changed __dev_printk and broke dynamic-debug's ability to control the
dynamic prefix of dev_dbg(dev,..).
dynamic_emit_prefix() adds "[tid] module:func:line:" to the output and
those additions got lost.
In addition, the current dynamic debug code uses up to 3 recursion
levels via %pV. This can consume quite a bit of stack. Directly
call printk_emit to reduce the recursion depth.
These changes include:
o Remove KERN_DEBUG from dynamic_emit_prefix
o Create and use function create_syslog_header to format the syslog
header for printk_emit uses.
o Call create_syslog_header and neaten __dev_printk
o Call create_syslog_header and printk_emit from dynamic_dev_dbg
o Call create_syslog_header and printk_emit from dynamic_netdev_dbg
o Make __dev_printk and __netdev_printk static not global
o Remove include header declarations of __dev_printk and __netdev_printk
o Remove now unused EXPORT_SYMBOL()s of __dev_printk and __netdev_printk
o Whitespace neatening
Changes in v2:
o Fix dynamic_emit_prefix to always initialize output
o Call create_syslog_header and emit_printk from__netdev_printk and
eliminate call to dev_printk to remove another recursion via %pV
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/base/core.c | 57 +++++++++++++++++++++++----------------
include/linux/device.h | 11 +++-----
include/linux/netdevice.h | 3 --
lib/dynamic_debug.c | 65 ++++++++++++++++++++++++++++++++++++---------
net/core/dev.c | 24 ++++++++++++-----
5 files changed, 106 insertions(+), 54 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f338037..d46b635 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1861,25 +1861,19 @@ void device_shutdown(void)
*/
#ifdef CONFIG_PRINTK
-int __dev_printk(const char *level, const struct device *dev,
- struct va_format *vaf)
+int create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen)
{
- char dict[128];
- size_t dictlen = 0;
const char *subsys;
-
- if (!dev)
- return printk("%s(NULL device *): %pV", level, vaf);
+ size_t pos = 0;
if (dev->class)
subsys = dev->class->name;
else if (dev->bus)
subsys = dev->bus->name;
else
- goto skip;
+ return 0;
- dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
- "SUBSYSTEM=%s", subsys);
+ pos += snprintf(hdr + pos, hdrlen - pos, "SUBSYSTEM=%s", subsys);
/*
* Add device identifier DEVICE=:
@@ -1895,28 +1889,41 @@ int __dev_printk(const char *level, const struct device *dev,
c = 'b';
else
c = 'c';
- dictlen++;
- dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
- "DEVICE=%c%u:%u",
- c, MAJOR(dev->devt), MINOR(dev->devt));
+ pos++;
+ pos += snprintf(hdr + pos, hdrlen - pos,
+ "DEVICE=%c%u:%u",
+ c, MAJOR(dev->devt), MINOR(dev->devt));
} else if (strcmp(subsys, "net") == 0) {
struct net_device *net = to_net_dev(dev);
- dictlen++;
- dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
- "DEVICE=n%u", net->ifindex);
+ pos++;
+ pos += snprintf(hdr + pos, hdrlen - pos,
+ "DEVICE=n%u", net->ifindex);
} else {
- dictlen++;
- dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
- "DEVICE=+%s:%s", subsys, dev_name(dev));
+ pos++;
+ pos += snprintf(hdr + pos, hdrlen - pos,
+ "DEVICE=+%s:%s", subsys, dev_name(dev));
}
-skip:
- return printk_emit(0, level[1] - '0',
- dictlen ? dict : NULL, dictlen,
+
+ return pos;
+}
+EXPORT_SYMBOL(create_syslog_header);
+
+static int __dev_printk(const char *level, const struct device *dev,
+ struct va_format *vaf)
+{
+ char hdr[128];
+ size_t hdrlen;
+
+ if (!dev)
+ return printk("%s(NULL device *): %pV", level, vaf);
+
+ hdrlen = create_syslog_header(dev, hdr, sizeof(hdr));
+
+ return printk_emit(0, level[1] - '0', hdrlen ? hdr : NULL, hdrlen,
"%s %s: %pV",
dev_driver_string(dev), dev_name(dev), vaf);
}
-EXPORT_SYMBOL(__dev_printk);
int dev_printk(const char *level, const struct device *dev,
const char *fmt, ...)
@@ -1931,6 +1938,7 @@ int dev_printk(const char *level, const struct device *dev,
vaf.va = &args;
r = __dev_printk(level, dev, &vaf);
+
va_end(args);
return r;
@@ -1950,6 +1958,7 @@ int func(const struct device *dev, const char *fmt, ...) \
vaf.va = &args; \
\
r = __dev_printk(kern_level, dev, &vaf); \
+ \
va_end(args); \
\
return r; \
diff --git a/include/linux/device.h b/include/linux/device.h
index 52a5f15..89b246c 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -891,12 +891,12 @@ extern const char *dev_driver_string(const struct device *dev);
#ifdef CONFIG_PRINTK
-extern int __dev_printk(const char *level, const struct device *dev,
- struct va_format *vaf);
+extern int create_syslog_header(const struct device *dev,
+ char *hdr, size_t hdrlen);
+
extern __printf(3, 4)
int dev_printk(const char *level, const struct device *dev,
- const char *fmt, ...)
- ;
+ const char *fmt, ...);
extern __printf(2, 3)
int dev_emerg(const struct device *dev, const char *fmt, ...);
extern __printf(2, 3)
@@ -914,9 +914,6 @@ int _dev_info(const struct device *dev, const char *fmt, ...);
#else
-static inline int __dev_printk(const char *level, const struct device *dev,
- struct va_format *vaf)
-{ return 0; }
static inline __printf(3, 4)
int dev_printk(const char *level, const struct device *dev,
const char *fmt, ...)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index eb06e58..291e0ee 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2715,9 +2715,6 @@ static inline const char *netdev_name(const struct net_device *dev)
return dev->name;
}
-extern int __netdev_printk(const char *level, const struct net_device *dev,
- struct va_format *vaf);
-
extern __printf(3, 4)
int netdev_printk(const char *level, const struct net_device *dev,
const char *format, ...);
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 7ca29a0..6b3ebab 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -521,25 +521,25 @@ static char *dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
int pos_after_tid;
int pos = 0;
- pos += snprintf(buf + pos, remaining(pos), "%s", KERN_DEBUG);
+ *buf = '\0';
+
if (desc->flags & _DPRINTK_FLAGS_INCL_TID) {
if (in_interrupt())
- pos += snprintf(buf + pos, remaining(pos), "%s ",
- "<intr>");
+ pos += snprintf(buf + pos, remaining(pos), "<intr> ");
else
pos += snprintf(buf + pos, remaining(pos), "[%d] ",
- task_pid_vnr(current));
+ task_pid_vnr(current));
}
pos_after_tid = pos;
if (desc->flags & _DPRINTK_FLAGS_INCL_MODNAME)
pos += snprintf(buf + pos, remaining(pos), "%s:",
- desc->modname);
+ desc->modname);
if (desc->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
pos += snprintf(buf + pos, remaining(pos), "%s:",
- desc->function);
+ desc->function);
if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
pos += snprintf(buf + pos, remaining(pos), "%d:",
- desc->lineno);
+ desc->lineno);
if (pos - pos_after_tid)
pos += snprintf(buf + pos, remaining(pos), " ");
if (pos >= PREFIX_SIZE)
@@ -559,9 +559,13 @@ int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
BUG_ON(!fmt);
va_start(args, fmt);
+
vaf.fmt = fmt;
vaf.va = &args;
- res = printk("%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf);
+
+ res = printk(KERN_DEBUG "%s%pV",
+ dynamic_emit_prefix(descriptor, buf), &vaf);
+
va_end(args);
return res;
@@ -574,15 +578,30 @@ int __dynamic_dev_dbg(struct _ddebug *descriptor,
struct va_format vaf;
va_list args;
int res;
- char buf[PREFIX_SIZE];
BUG_ON(!descriptor);
BUG_ON(!fmt);
va_start(args, fmt);
+
vaf.fmt = fmt;
vaf.va = &args;
- res = __dev_printk(dynamic_emit_prefix(descriptor, buf), dev, &vaf);
+
+ if (!dev) {
+ res = printk(KERN_DEBUG "(NULL device *): %pV", &vaf);
+ } else {
+ char buf[PREFIX_SIZE];
+ char dict[128];
+ size_t dictlen;
+
+ dictlen = create_syslog_header(dev, dict, sizeof(dict));
+
+ res = printk_emit(0, 7, dictlen ? dict : NULL, dictlen,
+ "%s%s %s: %pV",
+ dynamic_emit_prefix(descriptor, buf),
+ dev_driver_string(dev), dev_name(dev), &vaf);
+ }
+
va_end(args);
return res;
@@ -592,20 +611,40 @@ EXPORT_SYMBOL(__dynamic_dev_dbg);
#ifdef CONFIG_NET
int __dynamic_netdev_dbg(struct _ddebug *descriptor,
- const struct net_device *dev, const char *fmt, ...)
+ const struct net_device *dev, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
int res;
- char buf[PREFIX_SIZE];
BUG_ON(!descriptor);
BUG_ON(!fmt);
va_start(args, fmt);
+
vaf.fmt = fmt;
vaf.va = &args;
- res = __netdev_printk(dynamic_emit_prefix(descriptor, buf), dev, &vaf);
+
+ if (dev && dev->dev.parent) {
+ char buf[PREFIX_SIZE];
+ char dict[128];
+ size_t dictlen;
+
+ dictlen = create_syslog_header(dev->dev.parent,
+ dict, sizeof(dict));
+
+ res = printk_emit(0, 7, dictlen ? dict : NULL, dictlen,
+ "%s%s %s %s: %pV",
+ dynamic_emit_prefix(descriptor, buf),
+ dev_driver_string(dev->dev.parent),
+ dev_name(dev->dev.parent),
+ netdev_name(dev), &vaf);
+ } else if (dev) {
+ res = printk(KERN_DEBUG "%s: %pV", netdev_name(dev), &vaf);
+ } else {
+ res = printk(KERN_DEBUG "(NULL net_device): %pV", &vaf);
+ }
+
va_end(args);
return res;
diff --git a/net/core/dev.c b/net/core/dev.c
index 0ebaea1..c7bcea4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6358,22 +6358,30 @@ const char *netdev_drivername(const struct net_device *dev)
return empty;
}
-int __netdev_printk(const char *level, const struct net_device *dev,
+static int __netdev_printk(const char *level, const struct net_device *dev,
struct va_format *vaf)
{
int r;
- if (dev && dev->dev.parent)
- r = dev_printk(level, dev->dev.parent, "%s: %pV",
- netdev_name(dev), vaf);
- else if (dev)
+ if (dev && dev->dev.parent) {
+ char dict[128];
+ size_t dictlen = create_syslog_header(dev->dev.parent,
+ dict, sizeof(dict));
+
+ r = printk_emit(0, level[1] - '0',
+ dictlen ? dict : NULL, dictlen,
+ "%s %s %s: %pV",
+ dev_driver_string(dev->dev.parent),
+ dev_name(dev->dev.parent),
+ netdev_name(dev), &vaf);
+ } else if (dev) {
r = printk("%s%s: %pV", level, netdev_name(dev), vaf);
- else
+ } else {
r = printk("%s(NULL net_device): %pV", level, vaf);
+ }
return r;
}
-EXPORT_SYMBOL(__netdev_printk);
int netdev_printk(const char *level, const struct net_device *dev,
const char *format, ...)
@@ -6388,6 +6396,7 @@ int netdev_printk(const char *level, const struct net_device *dev,
vaf.va = &args;
r = __netdev_printk(level, dev, &vaf);
+
va_end(args);
return r;
@@ -6407,6 +6416,7 @@ int func(const struct net_device *dev, const char *fmt, ...) \
vaf.va = &args; \
\
r = __netdev_printk(level, dev, &vaf); \
+ \
va_end(args); \
\
return r; \
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* Re: [PATCH iproute2 v2] GRE over IPv6 tunnel support
From: David Miller @ 2012-07-28 7:58 UTC (permalink / raw)
To: xeb; +Cc: netdev
In-Reply-To: <20120728115226.66da9d77@comp1>
From: Dmitry Kozlov <xeb@mail.ru>
Date: Sat, 28 Jul 2012 11:52:26 +0400
> GRE over IPv6 tunnel support.
>
> Signed-off-by: Dmitry Kozlov <xeb@mail.ru>
> ---
> Changes:
> Implemented 'ip link' family of commands to manage
> ip6gre/ip6gretap tunnels.
Can you please stop sending your patches multiple times?
This is the second time you've done this today.
It makes extra work for us, because we have to keep blowing away the
spurious entries you keep adding to our automated patch queue at:
http://patchwork.ozlabs.org/project/netdev/list/
Thanks.
^ permalink raw reply
* Re: [GIT] Networking
From: Eric Dumazet @ 2012-07-28 8:41 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20120728.005241.2226926028836664098.davem@davemloft.net>
On Sat, 2012-07-28 at 00:52 -0700, David Miller wrote:
> Several bug fixes, some to new features appearing in this merge window,
> some that have been around for a while.
>
> I have a short list of known problems that need to be sorted out, but
> all of them can be solved easily during the run up to 3.6-final.
>
> I'll be offline until Sunday afternoon, but nothing need hold up
> 3.6-rc1 and the close of the merge window, networking wise, at this
> point.
>
> 1) Fix interface check in ipv4 TCP early demux, from Eric Dumazet.
trimming CC
I have some other TCP early demux issues, about RCU correctness
As we skb_dst_set_noref(skb, dst); in tcp_v{4|6}_early_demux,
we need to make sure we dont dst_release(sk->sk_rx_dst) if some in
flight skbs are still around.
So we probably need to respect an RCU grace period in dst_release()
before destroy.
Or we should set sk_rx_dst = dst only if dst hasnt DST_NOCACHE set ?
Also we need to remove rcu_read_lock() around ->early_demux() calls,
since we MUST already be in an rcu_read_lock() section.
RFC only patch, before running out for the week end ;)
include/net/inet_sock.h | 11 +++++++++++
net/ipv4/ip_input.c | 2 --
net/ipv4/tcp_input.c | 3 +--
net/ipv4/tcp_ipv4.c | 12 ++++++------
net/ipv4/tcp_minisocks.c | 3 +--
net/ipv6/ip6_input.c | 2 --
6 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 613cfa4..47b24d7 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -249,4 +249,15 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
return flags;
}
+static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb_dst(skb);
+
+ /* Can cache dst if rcu grace period is respected at dst destroy time */
+ if (!(dst->flags & DST_NOCACHE)) {
+ sk->sk_rx_dst = dst_clone(dst);
+ inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+ }
+}
+
#endif /* _INET_SOCK_H */
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 981ff1e..f1395a6 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -325,14 +325,12 @@ static int ip_rcv_finish(struct sk_buff *skb)
const struct net_protocol *ipprot;
int protocol = iph->protocol;
- rcu_read_lock();
ipprot = rcu_dereference(inet_protos[protocol]);
if (ipprot && ipprot->early_demux) {
ipprot->early_demux(skb);
/* must reload iph, skb->head might have changed */
iph = ip_hdr(skb);
}
- rcu_read_unlock();
}
/*
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index a356e1f..9be30b0 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5604,8 +5604,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
tcp_set_state(sk, TCP_ESTABLISHED);
if (skb != NULL) {
- sk->sk_rx_dst = dst_clone(skb_dst(skb));
- inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+ inet_sk_rx_dst_set(sk, skb);
security_inet_conn_established(sk, skb);
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 2fbd992..7f91e5a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1617,19 +1617,19 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
#endif
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
+ struct dst_entry *dst = sk->sk_rx_dst;
+
sock_rps_save_rxhash(sk, skb);
- if (sk->sk_rx_dst) {
- struct dst_entry *dst = sk->sk_rx_dst;
+ if (dst) {
if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
dst->ops->check(dst, 0) == NULL) {
dst_release(dst);
sk->sk_rx_dst = NULL;
}
}
- if (unlikely(sk->sk_rx_dst == NULL)) {
- sk->sk_rx_dst = dst_clone(skb_dst(skb));
- inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
- }
+ if (unlikely(!sk->sk_rx_dst))
+ inet_sk_rx_dst_set(sk, skb);
+
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
rsk = sk;
goto reset;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 3f1cc20..232a90c 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -387,8 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
struct tcp_sock *oldtp = tcp_sk(sk);
struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
- newsk->sk_rx_dst = dst_clone(skb_dst(skb));
- inet_sk(newsk)->rx_dst_ifindex = skb->skb_iif;
+ inet_sk_rx_dst_set(newsk, skb);
/* TCP Cookie Transactions require space for the cookie pair,
* as it differs for each connection. There is no need to
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 47975e3..a52d864 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -52,11 +52,9 @@ int ip6_rcv_finish(struct sk_buff *skb)
if (sysctl_ip_early_demux && !skb_dst(skb)) {
const struct inet6_protocol *ipprot;
- rcu_read_lock();
ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
if (ipprot && ipprot->early_demux)
ipprot->early_demux(skb);
- rcu_read_unlock();
}
if (!skb_dst(skb))
ip6_route_input(skb);
^ permalink raw reply related
* [PATCH] net:appletalk:ddp:fixed some codystyle issues in
From: Jeffrin Jose @ 2012-07-28 10:45 UTC (permalink / raw)
To: joe, acme, davem; +Cc: netdev, linux-kernel, ahiliation
Fixed coding style issues relating to indentation found in
net/appletalkddp.c."git diff -w" is empty and the compiled objects
are the same too.
Signed-off-by: Jeffrin Jose <ahiliation@yahoo.co.in>
---
net/appletalk/ddp.c | 212 +++++++++++++++++++++++++--------------------------
1 file changed, 106 insertions(+), 106 deletions(-)
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index c8bbcd2..19b7058 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -337,7 +337,7 @@ static int atif_proxy_probe_device(struct atalk_iface *atif,
return -EADDRINUSE; /* Network is full... */
}
-
+
struct atalk_addr *atalk_find_dev_addr(struct net_device *dev)
{
@@ -685,26 +685,26 @@ static int atif_ioctl(int cmd, void __user *arg)
switch (cmd) {
case SIOCSIFADDR:
- if (!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (sa->sat_family != AF_APPLETALK)
+ if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
- if (dev->type != ARPHRD_ETHER &&
- dev->type != ARPHRD_LOOPBACK &&
- dev->type != ARPHRD_LOCALTLK &&
- dev->type != ARPHRD_PPP)
+ if (dev->type != ARPHRD_ETHER &&
+ dev->type != ARPHRD_LOOPBACK &&
+ dev->type != ARPHRD_LOCALTLK &&
+ dev->type != ARPHRD_PPP)
return -EPROTONOSUPPORT;
- nr = (struct atalk_netrange *)&sa->sat_zero[0];
- add_route = 1;
+ nr = (struct atalk_netrange *)&sa->sat_zero[0];
+ add_route = 1;
- /*
- * if this is a point-to-point iface, and we already
- * have an iface for this AppleTalk address, then we
- * should not add a route
- */
- if ((dev->flags & IFF_POINTOPOINT) &&
- atalk_find_interface(sa->sat_addr.s_net,
+ /*
+ * if this is a point-to-point iface, and we already
+ * have an iface for this AppleTalk address, then we
+ * should not add a route
+ */
+ if ((dev->flags & IFF_POINTOPOINT) &&
+ atalk_find_interface(sa->sat_addr.s_net,
sa->sat_addr.s_node)) {
printk(KERN_DEBUG "AppleTalk: point-to-point "
"interface added with "
@@ -712,16 +712,16 @@ static int atif_ioctl(int cmd, void __user *arg)
add_route = 0;
}
- /*
- * Phase 1 is fine on LocalTalk but we don't do
- * EtherTalk phase 1. Anyone wanting to add it go ahead.
- */
- if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+ /*
+ * Phase 1 is fine on LocalTalk but we don't do
+ * EtherTalk phase 1. Anyone wanting to add it go ahead.
+ */
+ if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
return -EPROTONOSUPPORT;
- if (sa->sat_addr.s_node == ATADDR_BCAST ||
- sa->sat_addr.s_node == 254)
+ if (sa->sat_addr.s_node == ATADDR_BCAST ||
+ sa->sat_addr.s_node == 254)
return -EINVAL;
- if (atif) {
+ if (atif) {
/* Already setting address */
if (atif->status & ATIF_PROBE)
return -EBUSY;
@@ -734,36 +734,36 @@ static int atif_ioctl(int cmd, void __user *arg)
if (!atif)
return -ENOMEM;
}
- atif->nets = *nr;
+ atif->nets = *nr;
- /*
- * Check if the chosen address is used. If so we
- * error and atalkd will try another.
- */
+ /*
+ * Check if the chosen address is used. If so we
+ * error and atalkd will try another.
+ */
- if (!(dev->flags & IFF_LOOPBACK) &&
- !(dev->flags & IFF_POINTOPOINT) &&
- atif_probe_device(atif) < 0) {
- atif_drop_device(dev);
+ if (!(dev->flags & IFF_LOOPBACK) &&
+ !(dev->flags & IFF_POINTOPOINT) &&
+ atif_probe_device(atif) < 0) {
+ atif_drop_device(dev);
return -EADDRINUSE;
}
- /* Hey it worked - add the direct routes */
- sa = (struct sockaddr_at *)&rtdef.rt_gateway;
- sa->sat_family = AF_APPLETALK;
- sa->sat_addr.s_net = atif->address.s_net;
- sa->sat_addr.s_node = atif->address.s_node;
- sa = (struct sockaddr_at *)&rtdef.rt_dst;
- rtdef.rt_flags = RTF_UP;
- sa->sat_family = AF_APPLETALK;
- sa->sat_addr.s_node = ATADDR_ANYNODE;
- if (dev->flags & IFF_LOOPBACK ||
- dev->flags & IFF_POINTOPOINT)
+ /* Hey it worked - add the direct routes */
+ sa = (struct sockaddr_at *)&rtdef.rt_gateway;
+ sa->sat_family = AF_APPLETALK;
+ sa->sat_addr.s_net = atif->address.s_net;
+ sa->sat_addr.s_node = atif->address.s_node;
+ sa = (struct sockaddr_at *)&rtdef.rt_dst;
+ rtdef.rt_flags = RTF_UP;
+ sa->sat_family = AF_APPLETALK;
+ sa->sat_addr.s_node = ATADDR_ANYNODE;
+ if (dev->flags & IFF_LOOPBACK ||
+ dev->flags & IFF_POINTOPOINT)
rtdef.rt_flags |= RTF_HOST;
- /* Routerless initial state */
- if (nr->nr_firstnet == htons(0) &&
- nr->nr_lastnet == htons(0xFFFE)) {
+ /* Routerless initial state */
+ if (nr->nr_firstnet == htons(0) &&
+ nr->nr_lastnet == htons(0xFFFE)) {
sa->sat_addr.s_net = atif->address.s_net;
atrtr_create(&rtdef, dev);
atrtr_set_default(dev);
@@ -781,98 +781,98 @@ static int atif_ioctl(int cmd, void __user *arg)
atrtr_create(&rtdef, dev);
}
}
- dev_mc_add_global(dev, aarp_mcast);
- return 0;
+ dev_mc_add_global(dev, aarp_mcast);
+ return 0;
case SIOCGIFADDR:
- if (!atif)
- return -EADDRNOTAVAIL;
+ if (!atif)
+ return -EADDRNOTAVAIL;
- sa->sat_family = AF_APPLETALK;
- sa->sat_addr = atif->address;
- break;
+ sa->sat_family = AF_APPLETALK;
+ sa->sat_addr = atif->address;
+ break;
case SIOCGIFBRDADDR:
- if (!atif)
+ if (!atif)
return -EADDRNOTAVAIL;
- sa->sat_family = AF_APPLETALK;
- sa->sat_addr.s_net = atif->address.s_net;
- sa->sat_addr.s_node = ATADDR_BCAST;
- break;
+ sa->sat_family = AF_APPLETALK;
+ sa->sat_addr.s_net = atif->address.s_net;
+ sa->sat_addr.s_node = ATADDR_BCAST;
+ break;
case SIOCATALKDIFADDR:
case SIOCDIFADDR:
- if (!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (sa->sat_family != AF_APPLETALK)
+ if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
- atalk_dev_down(dev);
- break;
+ atalk_dev_down(dev);
+ break;
case SIOCSARP:
- if (!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (sa->sat_family != AF_APPLETALK)
+ if (sa->sat_family != AF_APPLETALK)
return -EINVAL;
- /*
- * for now, we only support proxy AARP on ELAP;
- * we should be able to do it for LocalTalk, too.
- */
- if (dev->type != ARPHRD_ETHER)
+ /*
+ * for now, we only support proxy AARP on ELAP;
+ * we should be able to do it for LocalTalk, too.
+ */
+ if (dev->type != ARPHRD_ETHER)
return -EPROTONOSUPPORT;
- /*
- * atif points to the current interface on this network;
- * we aren't concerned about its current status (at
- * least for now), but it has all the settings about
- * the network we're going to probe. Consequently, it
- * must exist.
- */
- if (!atif)
+ /*
+ * atif points to the current interface on this network;
+ * we aren't concerned about its current status (at
+ * least for now), but it has all the settings about
+ * the network we're going to probe. Consequently, it
+ * must exist.
+ */
+ if (!atif)
return -EADDRNOTAVAIL;
- nr = (struct atalk_netrange *)&(atif->nets);
- /*
- * Phase 1 is fine on Localtalk but we don't do
- * Ethertalk phase 1. Anyone wanting to add it go ahead.
- */
- if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
+ nr = (struct atalk_netrange *)&(atif->nets);
+ /*
+ * Phase 1 is fine on Localtalk but we don't do
+ * Ethertalk phase 1. Anyone wanting to add it go ahead.
+ */
+ if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)
return -EPROTONOSUPPORT;
- if (sa->sat_addr.s_node == ATADDR_BCAST ||
- sa->sat_addr.s_node == 254)
+ if (sa->sat_addr.s_node == ATADDR_BCAST ||
+ sa->sat_addr.s_node == 254)
return -EINVAL;
- /*
- * Check if the chosen address is used. If so we
- * error and ATCP will try another.
- */
- if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
+ /*
+ * Check if the chosen address is used. If so we
+ * error and ATCP will try another.
+ */
+ if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)
return -EADDRINUSE;
- /*
- * We now have an address on the local network, and
- * the AARP code will defend it for us until we take it
- * down. We don't set up any routes right now, because
- * ATCP will install them manually via SIOCADDRT.
- */
- break;
+ /*
+ * We now have an address on the local network, and
+ * the AARP code will defend it for us until we take it
+ * down. We don't set up any routes right now, because
+ * ATCP will install them manually via SIOCADDRT.
+ */
+ break;
case SIOCDARP:
- if (!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (sa->sat_family != AF_APPLETALK)
- return -EINVAL;
- if (!atif)
+ if (sa->sat_family != AF_APPLETALK)
+ return -EINVAL;
+ if (!atif)
return -EADDRNOTAVAIL;
- /* give to aarp module to remove proxy entry */
- aarp_proxy_remove(atif->dev, &(sa->sat_addr));
- return 0;
+ /* give to aarp module to remove proxy entry */
+ aarp_proxy_remove(atif->dev, &(sa->sat_addr));
+ return 0;
}
- return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0;
+ return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0;
}
/* Routing ioctl() calls */
--
1.7.10
^ permalink raw reply related
* Obtain an accredited degree in just 10 days. BA/BSc /MA/MSc/MBA/PhD. No classes or tests required. 100% legal method.
From: Ryan Jones @ 2012-07-28 11:35 UTC (permalink / raw)
To: ryanjones
Obtain an accredited degree in just 10 days. BA/BSc /MA/MSc/MBA/PhD. No classes or tests required. 100% legal method.
briefurl.net/71
^ permalink raw reply
* Re: [PATCH] net:appletalk:ddp:fixed some codystyle issues in
From: Joe Perches @ 2012-07-28 14:26 UTC (permalink / raw)
To: Jeffrin Jose; +Cc: acme, davem, netdev, linux-kernel
In-Reply-To: <1343472307-4697-1-git-send-email-ahiliation@yahoo.co.in>
On Sat, 2012-07-28 at 16:15 +0530, Jeffrin Jose wrote:
> Fixed coding style issues relating to indentation found in
> net/appletalkddp.c."git diff -w" is empty and the compiled objects
> are the same too.
Hello Jeffrin.
Your commit message is OK but your patch not.
The switch/case that could use modification is at
line 1790, not at line 685.
> diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
[]
> @@ -337,7 +337,7 @@ static int atif_proxy_probe_device(struct atalk_iface *atif,
>
> return -EADDRINUSE; /* Network is full... */
> }
> -
> +
Adding whitespace
> struct atalk_addr *atalk_find_dev_addr(struct net_device *dev)
> {
> @@ -685,26 +685,26 @@ static int atif_ioctl(int cmd, void __user *arg)
>
> switch (cmd) {
> case SIOCSIFADDR:
> - if (!capable(CAP_NET_ADMIN))
> + if (!capable(CAP_NET_ADMIN))
There's nothing wrong here to fix and you are
adding incorrect indentation.
Please try again and make sure you verify your
proposed patches by using scripts/checkpatch.pl
before submitting them.
^ permalink raw reply
* [PATCH] net: move "IPv6: sending pkt_too_big to self" to NETDEBUG
From: Philipp Kern @ 2012-07-28 15:06 UTC (permalink / raw)
To: linux-kernel
Cc: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, netdev, ak, Philipp Kern
ip6_xmit checks if the outgoing packet is larger than the path MTU and
emits ICMPv6 packet too big locally if this is the case. Logging this,
even at KERN_DEBUG, confuses users. It is also not actually helpful for
debugging, given that there is no reference to the connection that
triggered this event.
Hence move this message to LIMIT_NETDEBUG, as suggested by Andi Kleen
back in 2001 (<20010215231715.26269@colin.muc.de>).
Signed-off-by: Philipp Kern <pkern@debian.org>
---
net/ipv6/ip6_output.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5b2d63e..707002f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -241,7 +241,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
dst->dev, dst_output);
}
- net_dbg_ratelimited("IPv6: sending pkt_too_big to self\n");
+ LIMIT_NETDEBUG("IPv6: sending pkt_too_big to self\n");
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS);
--
1.7.10.4
^ permalink raw reply related
* ipv6: BUG: unable to handle kernel paging request at 0000000101bca2be
From: Cristian Rodríguez @ 2012-07-28 17:08 UTC (permalink / raw)
To: netdev
Hi:
Since late Jun, early Jul, both using stable 3.4 and now 3.5 I am
getting the following crash in the IPv6 code.
<1>[116145.466708] BUG: unable to handle kernel paging request at
0000000101bca2be
<1>[116145.467797] IP: [<ffffffff8145800b>] dst_release+0x1b/0x80
<4>[116145.468645] PGD 0
<4>[116145.468964] Oops: 0002 [#1] SMP
<4>[116145.469479] CPU 6
<4>[116145.469783] Modules linked in: bluetooth act_police cls_basic
cls_flow cls_fw cls_u32 sch_tbf sch_prio sch_htb sch_hfsc sch_ingress
sch_sfq bridge stp xt_statistic xt_CT xt_realm iptable_raw xt_LOG
xt_connlimit xt_addrtype xt_comment xt_recent ipt_ULOG ipt_REJECT
ipt_REDIRECT ipt_NETMAP ipt_MASQUERADE ipt_ECN ipt_CLUSTERIP ipt_ah
nf_nat_tftp nf_nat_snmp_basic nf_conntrack_snmp nf_nat_sip ip6_queue
nf_nat_pptp nf_nat_proto_gre xt_set ip_set nf_nat_irc nf_nat_h323
nf_nat_ftp nf_nat_amanda nf_conntrack_tftp nf_conntrack_sane
nf_conntrack_sip nf_conntrack_proto_udplite nf_conntrack_proto_sctp
ts_kmp nf_conntrack_pptp nf_conntrack_proto_gre nf_conntrack_amanda
nf_conntrack_netlink xt_time nf_conntrack_netbios_ns
nf_conntrack_broadcast xt_TCPMSS nf_conntrack_irc nf_conntrack_h323
xt_sctp xt_policy ip6t_REJECT nf_conntrack_ipv6 ip6table_raw
ip6table_mangle nf_conntrack_ftp xt_TPROXY nf_tproxy_core nf_defrag_ipv6
xt_tcpmss xt_pkttype xt_physdev xt_owner xt_NFQUEUE xt_NFLOG
nfnetlink_log xt_multiport xt_mark xt_mac xt_limit xt_length xt_iprange
xt_helper xt_hashlimit xt_DSCP xt_dscp xt_dccp xt_conntrack xt_connmark
xt_CLASSIFY xt_AUDIT xt_tcpudp xt_state ip6table_filter iptable_nat
nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 ip6_tables nf_conntrack
iptable_mangle nfnetlink iptable_filter ip_tables x_tables cachefiles
fscache af_packet edd eeepc_wmi asus_wmi sparse_keymap rfkill
pci_hotplug acpi_cpufreq mperf coretemp wmi iTCO_wdt crc32c_intel e1000e
mei(C) joydev pcspkr ghash_clmulni_intel iTCO_vendor_support i2c_i801
xhci_hcd aesni_intel cryptd aes_x86_64 microcode autofs4 usbhid i915
drm_kms_helper drm ehci_hcd i2c_algo_bit usbcore usb_common video button
scsi_dh_hp_sw scsi_dh_alua scsi_dh_emc scsi_dh_rdac scsi_dh fan
processor thermal thermal_sys megaraid_sas
<4>[116145.495352]
<4>[116145.495579] Pid: 0, comm: swapper/6 Tainted: G C
3.4.6-1-default #1 System manufacturer System Product Name/P8B WS
<4>[116145.497313] RIP: 0010:[<ffffffff8145800b>] [<ffffffff8145800b>]
dst_release+0x1b/0x80
<4>[116145.498527] RSP: 0018:ffff88041f383ce0 EFLAGS: 00010202
<4>[116145.499330] RAX: ffff8803c199e568 RBX: 0000000101bca23e RCX:
0000000000000000
<4>[116145.500407] RDX: 0000000101ba584e RSI: ffff8803c199e568 RDI:
0000000101bca23e
<4>[116145.501484] RBP: 00000000ffffffff R08: 0000000000000025 R09:
ffff88041f383cb0
<4>[116145.502560] R10: ffffffffa03f82e0 R11: ffff8803bf369886 R12:
ffff8803bf369886
<4>[116145.503636] R13: 0000000000000000 R14: 0000000000000500 R15:
ffff8803ff0de0c0
<4>[116145.504714] FS: 0000000000000000(0000) GS:ffff88041f380000(0000)
knlGS:0000000000000000
<4>[116145.505935] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
<4>[116145.506802] CR2: 0000000101bca2be CR3: 0000000001a0b000 CR4:
00000000000407e0
<4>[116145.507878] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
<4>[116145.508955] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7:
0000000000000400
<4>[116145.510033] Process swapper/6 (pid: 0, threadinfo
ffff88040a482000, task ffff88040a4800c0)
<4>[116145.511278] Stack:
<4>[116145.511582] 0000000002000000 00000000000249f0 ffff8803bf369896
ffffffff814f088a
<4>[116145.512754] ffff8804095fc000 ffff8803bf369896 ffff8803bf369886
ffffffff81d5fb80
<4>[116145.513926] 0000000000000500 ffff8804095fc000 000000000000003a
ffffffff814f0dca
<4>[116145.515100] Call Trace:
<4>[116145.515482] [<ffffffff814f088a>] rt6_do_pmtu_disc+0x27a/0x330
<4>[116145.516369] [<ffffffff814f0dca>] rt6_pmtu_discovery+0x3a/0x70
<4>[116145.517252] [<ffffffff81500423>] icmpv6_rcv+0x3c3/0x4a0
<4>[116145.563503] [<ffffffff814e44e7>] ip6_input_finish+0x157/0x380
<4>[116145.609526] [<ffffffff81450e93>] __netif_receive_skb+0x493/0x510
<4>[116145.655203] [<ffffffff81451901>] process_backlog+0xa1/0x170
<4>[116145.701481] [<ffffffff81451761>] net_rx_action+0x121/0x220
<4>[116145.748076] [<ffffffff810460ad>] __do_softirq+0x9d/0x1f0
<4>[116145.774285] [<ffffffff8155be0c>] call_softirq+0x1c/0x30
<4>[116145.800009] [<ffffffff81004195>] do_softirq+0x65/0xa0
<4>[116145.845329] [<ffffffff8104647e>] irq_exit+0x8e/0xb0
<4>[116145.890313] [<ffffffff8155b8da>]
call_function_single_interrupt+0x6a/0x70
<4>[116145.935988] [<ffffffff8131d4a9>] intel_idle+0xe9/0x160
<4>[116145.981862] [<ffffffff81418c2e>] cpuidle_idle_call+0x9e/0x280
<4>[116146.026965] [<ffffffff8100b53f>] cpu_idle+0x7f/0xd0
<4>[116146.069060] Code: ff 86 80 00 00 00 48 89 77 58 c3 0f 1f 44 00 00
48 83 ec 18 48 85 ff 48 89 5c 24 08 48 89 6c 24 10 48 89 fb 74 16 bd ff
ff ff ff <f0> 0f c1 af 80 00 00 00 83 ed 01 78 41 85 ed 74 14 48 8b 5c 24
<1>[116146.129910] RIP [<ffffffff8145800b>] dst_release+0x1b/0x80
<4>[116146.172426] RSP <ffff88041f383ce0>
<4>[116146.213632] CR2: 0000000101bca2be
It apparently appeared in either 3.4.3 or 3.4.4 and persist in 3.5..
Will be cool if someone can take a look...
^ permalink raw reply
* Re: [PATCH] net: move "IPv6: sending pkt_too_big to self" to NETDEBUG
From: Joe Perches @ 2012-07-28 17:29 UTC (permalink / raw)
To: Philipp Kern
Cc: linux-kernel, David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, netdev, ak
In-Reply-To: <1343487997-9047-1-git-send-email-pkern@debian.org>
On Sat, 2012-07-28 at 17:06 +0200, Philipp Kern wrote:
> ip6_xmit checks if the outgoing packet is larger than the path MTU and
> emits ICMPv6 packet too big locally if this is the case. Logging this,
> even at KERN_DEBUG, confuses users. It is also not actually helpful for
> debugging, given that there is no reference to the connection that
> triggered this event.
[]
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
[]
> @@ -241,7 +241,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
> dst->dev, dst_output);
> }
>
> - net_dbg_ratelimited("IPv6: sending pkt_too_big to self\n");
> + LIMIT_NETDEBUG("IPv6: sending pkt_too_big to self\n");
LIMIT_NETDEBUG doesn't include a logging level.
Add a KERN_DEBUG prefix or another KERN_<LEVEL>.
Maybe it'd be better to add the context too.
^ permalink raw reply
* Re: ipv6: BUG: unable to handle kernel paging request at 0000000101bca2be
From: Eric Dumazet @ 2012-07-28 19:08 UTC (permalink / raw)
To: Cristian Rodríguez; +Cc: netdev, Gao feng
In-Reply-To: <50141C95.3030602@opensuse.org>
On Sat, 2012-07-28 at 13:08 -0400, Cristian Rodríguez wrote:
> Hi:
>
> Since late Jun, early Jul, both using stable 3.4 and now 3.5 I am
> getting the following crash in the IPv6 code.
>
>
> <1>[116145.466708] BUG: unable to handle kernel paging request at
> 0000000101bca2be
> <1>[116145.467797] IP: [<ffffffff8145800b>] dst_release+0x1b/0x80
> <4>[116145.468645] PGD 0
> <4>[116145.468964] Oops: 0002 [#1] SMP
> <4>[116145.469479] CPU 6
> <4>[116145.469783] Modules linked in: bluetooth act_police cls_basic
> cls_flow cls_fw cls_u32 sch_tbf sch_prio sch_htb sch_hfsc sch_ingress
> sch_sfq bridge stp xt_statistic xt_CT xt_realm iptable_raw xt_LOG
> xt_connlimit xt_addrtype xt_comment xt_recent ipt_ULOG ipt_REJECT
> ipt_REDIRECT ipt_NETMAP ipt_MASQUERADE ipt_ECN ipt_CLUSTERIP ipt_ah
> nf_nat_tftp nf_nat_snmp_basic nf_conntrack_snmp nf_nat_sip ip6_queue
> nf_nat_pptp nf_nat_proto_gre xt_set ip_set nf_nat_irc nf_nat_h323
> nf_nat_ftp nf_nat_amanda nf_conntrack_tftp nf_conntrack_sane
> nf_conntrack_sip nf_conntrack_proto_udplite nf_conntrack_proto_sctp
> ts_kmp nf_conntrack_pptp nf_conntrack_proto_gre nf_conntrack_amanda
> nf_conntrack_netlink xt_time nf_conntrack_netbios_ns
> nf_conntrack_broadcast xt_TCPMSS nf_conntrack_irc nf_conntrack_h323
> xt_sctp xt_policy ip6t_REJECT nf_conntrack_ipv6 ip6table_raw
> ip6table_mangle nf_conntrack_ftp xt_TPROXY nf_tproxy_core nf_defrag_ipv6
> xt_tcpmss xt_pkttype xt_physdev xt_owner xt_NFQUEUE xt_NFLOG
> nfnetlink_log xt_multiport xt_mark xt_mac xt_limit xt_length xt_iprange
> xt_helper xt_hashlimit xt_DSCP xt_dscp xt_dccp xt_conntrack xt_connmark
> xt_CLASSIFY xt_AUDIT xt_tcpudp xt_state ip6table_filter iptable_nat
> nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 ip6_tables nf_conntrack
> iptable_mangle nfnetlink iptable_filter ip_tables x_tables cachefiles
> fscache af_packet edd eeepc_wmi asus_wmi sparse_keymap rfkill
> pci_hotplug acpi_cpufreq mperf coretemp wmi iTCO_wdt crc32c_intel e1000e
> mei(C) joydev pcspkr ghash_clmulni_intel iTCO_vendor_support i2c_i801
> xhci_hcd aesni_intel cryptd aes_x86_64 microcode autofs4 usbhid i915
> drm_kms_helper drm ehci_hcd i2c_algo_bit usbcore usb_common video button
> scsi_dh_hp_sw scsi_dh_alua scsi_dh_emc scsi_dh_rdac scsi_dh fan
> processor thermal thermal_sys megaraid_sas
> <4>[116145.495352]
> <4>[116145.495579] Pid: 0, comm: swapper/6 Tainted: G C
> 3.4.6-1-default #1 System manufacturer System Product Name/P8B WS
> <4>[116145.497313] RIP: 0010:[<ffffffff8145800b>] [<ffffffff8145800b>]
> dst_release+0x1b/0x80
> <4>[116145.498527] RSP: 0018:ffff88041f383ce0 EFLAGS: 00010202
> <4>[116145.499330] RAX: ffff8803c199e568 RBX: 0000000101bca23e RCX:
> 0000000000000000
> <4>[116145.500407] RDX: 0000000101ba584e RSI: ffff8803c199e568 RDI:
> 0000000101bca23e
> <4>[116145.501484] RBP: 00000000ffffffff R08: 0000000000000025 R09:
> ffff88041f383cb0
> <4>[116145.502560] R10: ffffffffa03f82e0 R11: ffff8803bf369886 R12:
> ffff8803bf369886
> <4>[116145.503636] R13: 0000000000000000 R14: 0000000000000500 R15:
> ffff8803ff0de0c0
> <4>[116145.504714] FS: 0000000000000000(0000) GS:ffff88041f380000(0000)
> knlGS:0000000000000000
> <4>[116145.505935] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
> <4>[116145.506802] CR2: 0000000101bca2be CR3: 0000000001a0b000 CR4:
> 00000000000407e0
> <4>[116145.507878] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> <4>[116145.508955] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7:
> 0000000000000400
> <4>[116145.510033] Process swapper/6 (pid: 0, threadinfo
> ffff88040a482000, task ffff88040a4800c0)
> <4>[116145.511278] Stack:
> <4>[116145.511582] 0000000002000000 00000000000249f0 ffff8803bf369896
> ffffffff814f088a
> <4>[116145.512754] ffff8804095fc000 ffff8803bf369896 ffff8803bf369886
> ffffffff81d5fb80
> <4>[116145.513926] 0000000000000500 ffff8804095fc000 000000000000003a
> ffffffff814f0dca
> <4>[116145.515100] Call Trace:
> <4>[116145.515482] [<ffffffff814f088a>] rt6_do_pmtu_disc+0x27a/0x330
> <4>[116145.516369] [<ffffffff814f0dca>] rt6_pmtu_discovery+0x3a/0x70
> <4>[116145.517252] [<ffffffff81500423>] icmpv6_rcv+0x3c3/0x4a0
> <4>[116145.563503] [<ffffffff814e44e7>] ip6_input_finish+0x157/0x380
> <4>[116145.609526] [<ffffffff81450e93>] __netif_receive_skb+0x493/0x510
> <4>[116145.655203] [<ffffffff81451901>] process_backlog+0xa1/0x170
> <4>[116145.701481] [<ffffffff81451761>] net_rx_action+0x121/0x220
> <4>[116145.748076] [<ffffffff810460ad>] __do_softirq+0x9d/0x1f0
> <4>[116145.774285] [<ffffffff8155be0c>] call_softirq+0x1c/0x30
> <4>[116145.800009] [<ffffffff81004195>] do_softirq+0x65/0xa0
> <4>[116145.845329] [<ffffffff8104647e>] irq_exit+0x8e/0xb0
> <4>[116145.890313] [<ffffffff8155b8da>]
> call_function_single_interrupt+0x6a/0x70
> <4>[116145.935988] [<ffffffff8131d4a9>] intel_idle+0xe9/0x160
> <4>[116145.981862] [<ffffffff81418c2e>] cpuidle_idle_call+0x9e/0x280
> <4>[116146.026965] [<ffffffff8100b53f>] cpu_idle+0x7f/0xd0
> <4>[116146.069060] Code: ff 86 80 00 00 00 48 89 77 58 c3 0f 1f 44 00 00
> 48 83 ec 18 48 85 ff 48 89 5c 24 08 48 89 6c 24 10 48 89 fb 74 16 bd ff
> ff ff ff <f0> 0f c1 af 80 00 00 00 83 ed 01 78 41 85 ed 74 14 48 8b 5c 24
> <1>[116146.129910] RIP [<ffffffff8145800b>] dst_release+0x1b/0x80
> <4>[116146.172426] RSP <ffff88041f383ce0>
> <4>[116146.213632] CR2: 0000000101bca2be
>
> It apparently appeared in either 3.4.3 or 3.4.4 and persist in 3.5..
>
> Will be cool if someone can take a look...
This looks like an error coming from commit
1716a96101c49186bb0b8491922fd3e69030235f
(ipv6: fix problem with expired dst cache)
dst_release() is called with a bogus dst pointer : 0000000101bca23e
rt6_clean_expires() seems to be called where it shouldnt.
Could you try reverting it ?
^ permalink raw reply
* Re: ipv6: BUG: unable to handle kernel paging request at 0000000101bca2be
From: Eric Dumazet @ 2012-07-28 19:21 UTC (permalink / raw)
To: Cristian Rodríguez; +Cc: netdev, Gao feng
In-Reply-To: <1343502509.2626.13172.camel@edumazet-glaptop>
On Sat, 2012-07-28 at 21:08 +0200, Eric Dumazet wrote:
> This looks like an error coming from commit
> 1716a96101c49186bb0b8491922fd3e69030235f
> (ipv6: fix problem with expired dst cache)
>
> dst_release() is called with a bogus dst pointer : 0000000101bca23e
>
> rt6_clean_expires() seems to be called where it shouldnt.
>
> Could you try reverting it ?
>
Or try following patch instead :
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 0ae759a..a85a865 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -123,13 +123,18 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
return ((struct rt6_info *)dst)->rt6i_idev;
}
+static inline void __rt6_clean_expires(struct rt6_info *rt)
+{
+ rt->rt6i_flags &= ~RTF_EXPIRES;
+ rt->dst.from = NULL;
+}
+
static inline void rt6_clean_expires(struct rt6_info *rt)
{
if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from)
dst_release(rt->dst.from);
- rt->rt6i_flags &= ~RTF_EXPIRES;
- rt->dst.from = NULL;
+ __rt6_clean_expires(rt);
}
static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index becb048..965f315 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -969,7 +969,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
rt->rt6i_gateway = ort->rt6i_gateway;
rt->rt6i_flags = ort->rt6i_flags;
- rt6_clean_expires(rt);
+ __rt6_clean_expires(rt);
rt->rt6i_metric = 0;
memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
@@ -1305,7 +1305,7 @@ int ip6_route_add(struct fib6_config *cfg)
rt6_set_expires(rt, jiffies +
clock_t_to_jiffies(cfg->fc_expires));
else
- rt6_clean_expires(rt);
+ __rt6_clean_expires(rt);
if (cfg->fc_protocol == RTPROT_UNSPEC)
cfg->fc_protocol = RTPROT_BOOT;
@@ -1837,7 +1837,7 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
(RTF_DEFAULT | RTF_ADDRCONF))
rt6_set_from(rt, ort);
else
- rt6_clean_expires(rt);
+ __rt6_clean_expires(rt);
rt->rt6i_metric = 0;
#ifdef CONFIG_IPV6_SUBTREES
^ permalink raw reply related
* Re: [PATCH net-next v2] GRE over IPv6
From: Eric W. Biederman @ 2012-07-28 20:16 UTC (permalink / raw)
To: Dmitry Kozlov; +Cc: netdev
In-Reply-To: <20120728113512.3ffd8248@comp1>
Dmitry Kozlov <xeb@mail.ru> writes:
> GRE over IPv6 implementation.
Why are you implementing an ioctl based instead of using netlink?
Last I looked using netlink to create and delete tunnels was more
flexible and the preferred method and the existing ioctl based methods
were simply being maintained for backwards compatibility.
Also it appears that you have failed to include the all important
ip6_gre.c
Eric
> Signed-off-by: Dmitry Kozlov <xeb@mail.ru>
> ---
> Changes:
> Initialize nt->dev before calling ip6gre_tnl_link_config in
> ip6gre_newlink.
>
> include/linux/if_arp.h | 1 +
> include/linux/if_tunnel.h | 3 ++> include/linux/ip6_tunnel.h | 18 +++++++++
> include/net/ip6_tunnel.h | 40 ++++++++++++++++++++-
> include/net/ipv6.h | 1 +
> net/ipv6/Kconfig | 16 ++++++++
> net/ipv6/Makefile | 1 +
> net/ipv6/ip6_tunnel.c | 86 +++++++++++++++++++++++++++++++------------
> 8 files changed, 141 insertions(+), 25 deletions(-)
>
> diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
> index f0e69c6..9adcc29 100644
> --- a/include/linux/if_arp.h
> +++ b/include/linux/if_arp.h
> @@ -92,6 +92,7 @@
> #define ARPHRD_PHONET 820 /* PhoNet media type */
> #define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */
> #define ARPHRD_CAIF 822 /* CAIF media type */
> +#define ARPHRD_IP6GRE 823 /* GRE over IPv6
> */
You don't use this #define why introduce it?
>
> #define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
> #define ARPHRD_NONE 0xFFFE /* zero header length */
> diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
> index 5efff60..8c5035a 100644
> --- a/include/linux/if_tunnel.h
> +++ b/include/linux/if_tunnel.h
> @@ -75,6 +75,9 @@ enum {
> IFLA_GRE_TTL,
> IFLA_GRE_TOS,
> IFLA_GRE_PMTUDISC,
> + IFLA_GRE_ENCAP_LIMIT,
> + IFLA_GRE_FLOWINFO,
> + IFLA_GRE_FLAGS,
> __IFLA_GRE_MAX,
> };
>
> diff --git a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h
> index bf22b03..1efe2e0 100644
> --- a/include/linux/ip6_tunnel.h
> +++ b/include/linux/ip6_tunnel.h
> @@ -31,4 +31,22 @@ struct ip6_tnl_parm {
> struct in6_addr raddr; /* remote tunnel end-point address */
> };
>
> +struct ip6_tnl_parm2 {
> + char name[IFNAMSIZ]; /* name of tunnel device */
> + int link; /* ifindex of underlying L2 interface */
> + __u8 proto; /* tunnel protocol */
> + __u8 encap_limit; /* encapsulation limit for tunnel */
> + __u8 hop_limit; /* hop limit for tunnel */
> + __be32 flowinfo; /* traffic class and flowlabel for tunnel */
> + __u32 flags; /* tunnel flags */
> + struct in6_addr laddr; /* local tunnel end-point address */
> + struct in6_addr raddr; /* remote tunnel end-point address */
> +
> + __be16 i_flags;
> + __be16 o_flags;
> + __be32 i_key;
> + __be32 o_key;
> +};
> +
> +
> #endif
> diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
> index 358fb86..8400ba0 100644
> --- a/include/net/ip6_tunnel.h
> +++ b/include/net/ip6_tunnel.h
> @@ -5,6 +5,8 @@
> #include <linux/netdevice.h>
> #include <linux/ip6_tunnel.h>
>
> +#define IP6TUNNEL_ERR_TIMEO (30*HZ)
> +
> /* capable of sending packets */
> #define IP6_TNL_F_CAP_XMIT 0x10000
> /* capable of receiving packets */
> @@ -13,14 +15,40 @@
> #define IP6_TNL_F_CAP_PER_PACKET 0x40000
>
> /* IPv6 tunnel */
> +struct __ip6_tnl_parm
> +{
> + char name[IFNAMSIZ]; /* name of tunnel device */
> + int link; /* ifindex of underlying L2 interface */
> + __u8 proto; /* tunnel protocol */
> + __u8 encap_limit; /* encapsulation limit for tunnel */
> + __u8 hop_limit; /* hop limit for tunnel */
> + __be32 flowinfo; /* traffic class and flowlabel for tunnel */
> + __u32 flags; /* tunnel flags */
> + struct in6_addr laddr; /* local tunnel end-point address */
> + struct in6_addr raddr; /* remote tunnel end-point address */
> +
> + __be16 i_flags;
> + __be16 o_flags;
> + __be32 i_key;
> + __be32 o_key;
> +};
>
> struct ip6_tnl {
> struct ip6_tnl __rcu *next; /* next tunnel in list */
> struct net_device *dev; /* virtual device associated with tunnel */
> - struct ip6_tnl_parm parms; /* tunnel configuration parameters */
> + struct __ip6_tnl_parm parms; /* tunnel configuration parameters */
> struct flowi fl; /* flowi template for xmit */
> struct dst_entry *dst_cache; /* cached dst */
> u32 dst_cookie;
> +
> + int err_count;
> + unsigned long err_time;
> +
> + /* These fields used only by GRE */
> + __u32 i_seqno; /* The last seen seqno */
> + __u32 o_seqno; /* The last output seqno */
> + int hlen; /* Precalculated GRE header length */
> + int mlink;
> };
>
> /* Tunnel encapsulation limit destination sub-option */
> @@ -31,4 +59,14 @@ struct ipv6_tlv_tnl_enc_lim {
> __u8 encap_limit; /* tunnel encapsulation limit */
> } __packed;
>
> +struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t);
> +void ip6_tnl_dst_reset(struct ip6_tnl *t);
> +void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst);
> +int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
> + const struct in6_addr *raddr);
> +int ip6_tnl_xmit_ctl(struct ip6_tnl *t);
> +__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 * raw);
> +__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
> + const struct in6_addr *raddr);
> +
> #endif
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index 01c34b3..6d01fb0 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -34,6 +34,7 @@
> #define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */
> #define NEXTHDR_ROUTING 43 /* Routing header. */
> #define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */
> +#define NEXTHDR_GRE 47 /* GRE header. */
You don't use this define why introduce it?
> #define NEXTHDR_ESP 50 /* Encapsulating security payload. */
> #define NEXTHDR_AUTH 51 /* Authentication header. */
> #define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
> diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
> index 5728695..4f7fe72 100644
> --- a/net/ipv6/Kconfig
> +++ b/net/ipv6/Kconfig
> @@ -201,6 +201,22 @@ config IPV6_TUNNEL
>
> If unsure, say N.
>
> +config IPV6_GRE
> + tristate "IPv6: GRE tunnel"
> + select IPV6_TUNNEL
> + ---help---
> + Tunneling means encapsulating data of one protocol type within
> + another protocol and sending it over a channel that understands the
> + encapsulating protocol. This particular tunneling driver implements
> + GRE (Generic Routing Encapsulation) and at this time allows
> + encapsulating of IPv4 or IPv6 over existing IPv6 infrastructure.
> + This driver is useful if the other endpoint is a Cisco router: Cisco
> + likes GRE much better than the other Linux tunneling driver ("IP
> + tunneling" above). In addition, GRE allows multicast redistribution
> + through the tunnel.
> +
> + Saying M here will produce a module called ip6_gre. If unsure, say N.
> +
> config IPV6_MULTIPLE_TABLES
> bool "IPv6: Multiple Routing Tables"
> depends on EXPERIMENTAL
> diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
> index 686934a..b6d3f79 100644
> --- a/net/ipv6/Makefile
> +++ b/net/ipv6/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/
>
> obj-$(CONFIG_IPV6_SIT) += sit.o
> obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
> +obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
>
> obj-y += addrconf_core.o exthdrs_core.o
>
> diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
> index 9a1d5fe..fc24522 100644
> --- a/net/ipv6/ip6_tunnel.c
> +++ b/net/ipv6/ip6_tunnel.c
> @@ -126,7 +126,7 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
> * Locking : hash tables are protected by RCU and RTNL
> */
>
> -static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
> +struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
> {
> struct dst_entry *dst = t->dst_cache;
>
> @@ -139,20 +139,23 @@ static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
>
> return dst;
> }
> +EXPORT_SYMBOL_GPL(ip6_tnl_dst_check);
>
> -static inline void ip6_tnl_dst_reset(struct ip6_tnl *t)
> +void ip6_tnl_dst_reset(struct ip6_tnl *t)
> {
> dst_release(t->dst_cache);
> t->dst_cache = NULL;
> }
> +EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
>
> -static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
> +void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
> {
> struct rt6_info *rt = (struct rt6_info *) dst;
> t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
> dst_release(t->dst_cache);
> t->dst_cache = dst;
> }
> +EXPORT_SYMBOL_GPL(ip6_tnl_dst_store);
>
> /**
> * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
> @@ -200,7 +203,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_
> **/
>
> static struct ip6_tnl __rcu **
> -ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p)
> +ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p)
> {
> const struct in6_addr *remote = &p->raddr;
> const struct in6_addr *local = &p->laddr;
> @@ -267,7 +270,7 @@ static void ip6_dev_free(struct net_device *dev)
> * created tunnel or NULL
> **/
>
> -static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
> +static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
> {
> struct net_device *dev;
> struct ip6_tnl *t;
> @@ -322,7 +325,7 @@ failed:
> **/
>
> static struct ip6_tnl *ip6_tnl_locate(struct net *net,
> - struct ip6_tnl_parm *p, int create)
> + struct __ip6_tnl_parm *p, int create)
> {
> const struct in6_addr *remote = &p->raddr;
> const struct in6_addr *local = &p->laddr;
> @@ -374,8 +377,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)
> * else index to encapsulation limit
> **/
>
> -static __u16
> -parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
> +__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 * raw)
> {
> const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
> __u8 nexthdr = ipv6h->nexthdr;
> @@ -425,6 +427,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
> }
> return 0;
> }
> +EXPORT_SYMBOL(ip6_tnl_parse_tlv_enc_lim);
>
> /**
> * ip6_tnl_err - tunnel error handler
> @@ -480,7 +483,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
> case ICMPV6_PARAMPROB:
> teli = 0;
> if ((*code) == ICMPV6_HDR_FIELD)
> - teli = parse_tlv_tnl_enc_lim(skb, skb->data);
> + teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data);
>
> if (teli && teli == *info - 2) {
> tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
> @@ -693,11 +696,11 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
> IP6_ECN_set_ce(ipv6_hdr(skb));
> }
>
> -static __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
> +__u32 ip6_tnl_get_cap(struct ip6_tnl *t,
> const struct in6_addr *laddr,
> const struct in6_addr *raddr)
> {
> - struct ip6_tnl_parm *p = &t->parms;
> + struct __ip6_tnl_parm *p = &t->parms;
> int ltype = ipv6_addr_type(laddr);
> int rtype = ipv6_addr_type(raddr);
> __u32 flags = 0;
> @@ -715,13 +718,14 @@ static __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
> }
> return flags;
> }
> +EXPORT_SYMBOL(ip6_tnl_get_cap);
>
> /* called with rcu_read_lock() */
> -static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
> +int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
> const struct in6_addr *laddr,
> const struct in6_addr *raddr)
> {
> - struct ip6_tnl_parm *p = &t->parms;
> + struct __ip6_tnl_parm *p = &t->parms;
> int ret = 0;
> struct net *net = dev_net(t->dev);
>
> @@ -740,6 +744,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
> }
> return ret;
> }
> +EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
>
> /**
> * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
> @@ -859,9 +864,9 @@ ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
> return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
> }
>
> -static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
> +int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
> {
> - struct ip6_tnl_parm *p = &t->parms;
> + struct __ip6_tnl_parm *p = &t->parms;
> int ret = 0;
> struct net *net = dev_net(t->dev);
>
> @@ -885,6 +890,8 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
> }
> return ret;
> }
> +EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
> +
> /**
> * ip6_tnl_xmit2 - encapsulate packet and send
> * @skb: the outgoing socket buffer
> @@ -1085,7 +1092,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
> !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
> return -1;
>
> - offset = parse_tlv_tnl_enc_lim(skb, skb_network_header(skb));
> + offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
> if (offset > 0) {
> struct ipv6_tlv_tnl_enc_lim *tel;
> tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
> @@ -1152,7 +1159,7 @@ tx_err:
> static void ip6_tnl_link_config(struct ip6_tnl *t)
> {
> struct net_device *dev = t->dev;
> - struct ip6_tnl_parm *p = &t->parms;
> + struct __ip6_tnl_parm *p = &t->parms;
> struct flowi6 *fl6 = &t->fl.u.ip6;
>
> memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
> @@ -1215,7 +1222,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
> **/
>
> static int
> -ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
> +ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
> {
> t->parms.laddr = p->laddr;
> t->parms.raddr = p->raddr;
> @@ -1230,6 +1237,32 @@ ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
> return 0;
> }
>
> +static void ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
> +{
> + p->laddr = u->laddr;
> + p->raddr = u->raddr;
> + p->flags = u->flags;
> + p->hop_limit = u->hop_limit;
> + p->encap_limit = u->encap_limit;
> + p->flowinfo = u->flowinfo;
> + p->link = u->link;
> + p->proto = u->proto;
> + memcpy(p->name, u->name, sizeof(u->name));
> +}
> +
> +static void ip6_tnl_parm_to_user(struct ip6_tnl_parm *u, const struct __ip6_tnl_parm *p)
> +{
> + u->laddr = p->laddr;
> + u->raddr = p->raddr;
> + u->flags = p->flags;
> + u->hop_limit = p->hop_limit;
> + u->encap_limit = p->encap_limit;
> + u->flowinfo = p->flowinfo;
> + u->link = p->link;
> + u->proto = p->proto;
> + memcpy(u->name, p->name, sizeof(u->name));
> +}
> +
> /**
> * ip6_tnl_ioctl - configure ipv6 tunnels from userspace
> * @dev: virtual device associated with tunnel
> @@ -1263,6 +1296,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
> {
> int err = 0;
> struct ip6_tnl_parm p;
> + struct __ip6_tnl_parm p1;
> struct ip6_tnl *t = NULL;
> struct net *net = dev_net(dev);
> struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
> @@ -1274,11 +1308,12 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
> err = -EFAULT;
> break;
> }
> - t = ip6_tnl_locate(net, &p, 0);
> + ip6_tnl_parm_from_user(&p1, &p);
> + t = ip6_tnl_locate(net, &p1, 0);
> }
> if (t == NULL)
> t = netdev_priv(dev);
> - memcpy(&p, &t->parms, sizeof (p));
> + ip6_tnl_parm_to_user(&p, &t->parms);
> if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
> err = -EFAULT;
> }
> @@ -1295,7 +1330,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
> if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
> p.proto != 0)
> break;
> - t = ip6_tnl_locate(net, &p, cmd == SIOCADDTUNNEL);
> + ip6_tnl_parm_from_user(&p1, &p);
> + t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
> if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
> if (t != NULL) {
> if (t->dev != dev) {
> @@ -1307,13 +1343,14 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
>
> ip6_tnl_unlink(ip6n, t);
> synchronize_net();
> - err = ip6_tnl_change(t, &p);
> + err = ip6_tnl_change(t, &p1);
> ip6_tnl_link(ip6n, t);
> netdev_state_change(dev);
> }
> if (t) {
> err = 0;
> - if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof (p)))
> + ip6_tnl_parm_to_user(&p, &t->parms);
> + if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p)))
> err = -EFAULT;
>
> } else
> @@ -1329,7 +1366,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
> if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
> break;
> err = -ENOENT;
> - if ((t = ip6_tnl_locate(net, &p, 0)) == NULL)
> + ip6_tnl_parm_from_user(&p1, &p);
> + if ((t = ip6_tnl_locate(net, &p1, 0)) == NULL)
> break;
> err = -EPERM;
> if (t->dev == ip6n->fb_tnl_dev)
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox