* Re: [PATCH 01/31] net: ax88796: use dev_get_platdata()
From: Sergei Shtylyov @ 2013-08-31 18:14 UTC (permalink / raw)
To: Jingoo Han; +Cc: 'David S. Miller', netdev
In-Reply-To: <003101cea53b$9fc95b30$df5c1190$%han@samsung.com>
Hello.
On 08/30/2013 08:44 AM, Jingoo Han wrote:
> Use the wrapper function for retrieving the platform data instead of
> accessing dev->platform_data directly. This is a cosmetic change
> to make the code simpler and enhance the readability.
This hardly achieves either...
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
> ---
> drivers/net/ethernet/8390/ax88796.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
> diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
> index b7232a9..f92f001 100644
> --- a/drivers/net/ethernet/8390/ax88796.c
> +++ b/drivers/net/ethernet/8390/ax88796.c
> @@ -840,7 +840,7 @@ static int ax_probe(struct platform_device *pdev)
> ei_local = netdev_priv(dev);
> ax = to_ax_dev(dev);
>
> - ax->plat = pdev->dev.platform_data;
> + ax->plat = dev_get_platdata(&pdev->dev);
> platform_set_drvdata(pdev, dev);
>
> ei_local->rxcr_base = ax->plat->rcr_val;
WBR, Sergei
^ permalink raw reply
* Re: [iproute2] macvlan: fix typo in macvlan_print_opt()
From: Stephen Hemminger @ 2013-08-31 17:32 UTC (permalink / raw)
To: Lutz Jaenicke; +Cc: netdev
In-Reply-To: <1377762628-28843-1-git-send-email-ljaenicke@innominate.com>
On Thu, 29 Aug 2013 09:50:28 +0200
Lutz Jaenicke <ljaenicke@innominate.com> wrote:
> The mode information is contained in IFLA_MACVLAN_MODE instead
> of IFLA_VLAN_ID (both evaluating to "1" in their enums).
>
> Signed-off-by: Lutz Jaenicke <ljaenicke@innominate.com>
Thanks applied.
^ permalink raw reply
* Re: [PATCH] iproute2: ip-route.8.in: minor fixes
From: Stephen Hemminger @ 2013-08-31 17:31 UTC (permalink / raw)
To: Richard Godbee; +Cc: netdev
In-Reply-To: <1377484819-23743-2-git-send-email-richard@godbee.net>
On Sun, 25 Aug 2013 22:40:19 -0400
Richard Godbee <richard@godbee.net> wrote:
> In SYNOPSIS section:
>
> - Add 'reordering'
> - Add missing '[' before 'quickack'
>
> Signed-off-by: Richard Godbee <richard@godbee.net>
All applied, thanks
^ permalink raw reply
* Re: [PATCH net-next v12 06/11] vxlan: add ipv6 support
From: Stephen Hemminger @ 2013-08-31 17:27 UTC (permalink / raw)
To: Cong Wang; +Cc: netdev, David S. Miller, David Stevens
In-Reply-To: <1377927878-23975-7-git-send-email-amwang@redhat.com>
On Sat, 31 Aug 2013 13:44:33 +0800
Cong Wang <amwang@redhat.com> wrote:
> +#if IS_ENABLED(CONFIG_IPV6)
> + } else {
> + ipv6_stub->ipv6_sock_mc_join(sk, ifindex,
> + &ip->sin6.sin6_addr);
> +#endif
This isn't safe against IPv6 module getting unloaded. You either
have to figure out a reference count method, or disable IPv6
module unload.
Since it can only be forced unload anyway, I still argue
it should just be disabled (by removing the module exit hook
and code).
^ permalink raw reply
* [BUG] missing rcu_derefernce of txq->qdisc
From: Stephen Hemminger @ 2013-08-31 17:23 UTC (permalink / raw)
To: David Miller, Joe Perches; +Cc: netdev
Way back in 2008, this commit added rcu_assign_pointer for the dev_queue->qdisc.
But we aren't using rcu_dereference to fetch the pointer, here and a couple
of other places. This is probably harmless, but could cause issues when compiler
decides to optimizations because of missing barrier.
static inline void netif_schedule_queue(struct netdev_queue *txq)
{
if (!(txq->state & QUEUE_STATE_ANY_XOFF))
__netif_schedule(txq->qdisc);
}
Adding the needed rcu_dereference creates other problems because the the
struct Qdisc needs to be fully known, net/sch_generic.h has to be included
from netdevice.h which creates other build problems.
A good way to see all the fallout is to put needed __rcu annotation
on netdev_tx_queue qdisc and use sparse.
I don't have time or patience to deal with it right now, maybe someone
else could have a go at it.
^ permalink raw reply
* [PATCH net-next 1/2] qdisc: make args to qdisc_create_default const
From: Stephen Hemminger @ 2013-08-31 17:15 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Fixes warnings introduced by the qdisc default patch.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
--- a/include/net/sch_generic.h 2013-08-31 09:40:20.933206054 -0700
+++ b/include/net/sch_generic.h 2013-08-31 09:50:18.309178508 -0700
@@ -370,9 +370,9 @@ void qdisc_reset(struct Qdisc *qdisc);
void qdisc_destroy(struct Qdisc *qdisc);
void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
- struct Qdisc_ops *ops);
+ const struct Qdisc_ops *ops);
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
- struct Qdisc_ops *ops, u32 parentid);
+ const struct Qdisc_ops *ops, u32 parentid);
void __qdisc_calculate_pkt_len(struct sk_buff *skb,
const struct qdisc_size_table *stab);
void tcf_destroy(struct tcf_proto *tp);
--- a/net/sched/sch_generic.c 2013-08-31 09:40:20.949205839 -0700
+++ b/net/sched/sch_generic.c 2013-08-31 09:50:18.313178455 -0700
@@ -534,7 +534,7 @@ struct Qdisc_ops pfifo_fast_ops __read_m
static struct lock_class_key qdisc_tx_busylock;
struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
- struct Qdisc_ops *ops)
+ const struct Qdisc_ops *ops)
{
void *p;
struct Qdisc *sch;
@@ -578,7 +578,8 @@ errout:
}
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
- struct Qdisc_ops *ops, unsigned int parentid)
+ const struct Qdisc_ops *ops,
+ unsigned int parentid)
{
struct Qdisc *sch;
^ permalink raw reply
* Re: [PATCH net-next 2/2] qdisc: fix build with !CONFIG_NET_SCHED
From: Stephen Hemminger @ 2013-08-31 17:15 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20130831100442.60c99dc8@nehalam.linuxnetplumber.net>
Multiqueue scheduler refers to default_qdisc_ops; therefore the
variable definition needs to be moved to handle case where net
scheduler API is not available.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
--- a/net/sched/sch_api.c 2013-08-31 09:40:20.949205839 -0700
+++ b/net/sched/sch_api.c 2013-08-31 10:01:45.811672724 -0700
@@ -131,11 +131,6 @@ static DEFINE_RWLOCK(qdisc_mod_lock);
************************************************/
-/* Qdisc to use by default */
-
-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
-EXPORT_SYMBOL(default_qdisc_ops);
-
/* The list of all installed queueing disciplines. */
static struct Qdisc_ops *qdisc_base;
--- a/net/sched/sch_generic.c 2013-08-31 09:50:18.313178455 -0700
+++ b/net/sched/sch_generic.c 2013-08-31 10:02:10.699323182 -0700
@@ -30,6 +30,10 @@
#include <net/pkt_sched.h>
#include <net/dst.h>
+/* Qdisc to use by default */
+const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
+EXPORT_SYMBOL(default_qdisc_ops);
+
/* Main transmission queue. */
/* Modifications to data participating in scheduling must be protected with
^ permalink raw reply
* Re: [E1000-devel] [PATCH] i40e: Fix 32 bit shift compilation warnings
From: Stephen Hemminger @ 2013-08-31 16:45 UTC (permalink / raw)
To: Joe Perches
Cc: Jeff Kirsher, e1000-devel, Bruce Allan, Jesse Brandeburg,
linux-kernel, John Ronciak, netdev
In-Reply-To: <1377913655.2070.45.camel@joe-AO722>
On Fri, 30 Aug 2013 18:47:35 -0700
Joe Perches <joe@perches.com> wrote:
> When dma_addr_t is a 32 bit value, >> 32 emits compiler warnings
> Use ((addr>>16) >>16) to avoid this.
>
> I presume the macro should actually use the kernel.h
> macro upper_32_bits() eventually.
>
> Signed-off-by: Joe Perches <joe@perches.com>
> ---
> drivers/net/ethernet/intel/i40e/i40e_hmc.h | 2 +-
> drivers/net/ethernet/intel/i40e/i40e_type.h | 4 ++--
> 2 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h
> index 745fb355..2f1b72f 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h
> @@ -123,7 +123,7 @@ struct i40e_hmc_info {
> #define I40E_SET_PF_SD_ENTRY(hw, pa, sd_index, type) \
> { \
> u32 val1, val2, val3; \
> - val1 = (u32)((pa) >> sizeof(u32) * 8); \
> + val1 = (u32)(I40E_HI_DWORD(pa)); \
> val2 = (u32)(pa) | (I40E_HMC_MAX_BP_COUNT << \
> I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \
> ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
> index 36e35cc..4263cf7 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
> @@ -78,8 +78,8 @@ typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *);
> #define I40E_ETH_LENGTH_OF_ADDRESS 6
>
> /* Data type manipulation macros. */
> -#define I40E_HI_DWORD(x) ((u32)(((x)>>32)&0xFFFFFFFF))
> -#define I40E_LO_DWORD(x) ((u32)((x)&0xFFFFFFFF))
> +#define I40E_HI_DWORD(x) ((u32)((((x) >> 16) >> 16) & 0xFFFFFFFF))
> +#define I40E_LO_DWORD(x) ((u32)((x) & 0xFFFFFFFF))
>
> #define I40E_HI_WORD(x) ((u16)(((x)>>16)&0xFFFF))
> #define I40E_DESC_UNUSED(R) \
After seeing this before in other drivers, a standard set of macros
was added called upper_32bits and lower_32bits. These should be used instead
of masking.
^ permalink raw reply
* Re: [PATCH net-next] etherdevice: Optimize compare_ether_addr/ether_addr_equal
From: Stephen Hemminger @ 2013-08-31 16:43 UTC (permalink / raw)
To: Joe Perches; +Cc: David Miller, Eric Dumazet, netdev
In-Reply-To: <1377939256.2054.11.camel@joe-AO722>
On Sat, 31 Aug 2013 01:54:16 -0700
Joe Perches <joe@perches.com> wrote:
> When CONFIG_HAS_EFFICIENT_UNALIGNED_ACCESS is set,
> optimize compare_ether_addr a little by removing an
> xor and or by using a u32 and u16 comparison
> instead of 3 separate u16 comparisons.
>
> Make the ether_addr_equal_64bits code a bit simpler
> by adding a test for CONFIG_64BIT and calling
> ether_addr_equal otherwise.
>
> This also slightly improves ether_addr_equal_64bits
> by removing the zap_last_2bytes shifts in the !64bit
> case.
>
> Signed-off-by: Joe Perches <joe@perches.com>
> ---
> include/linux/etherdevice.h | 17 ++++++++++-------
> 1 file changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
> index c623861..2514d17 100644
> --- a/include/linux/etherdevice.h
> +++ b/include/linux/etherdevice.h
> @@ -208,11 +208,19 @@ static inline void eth_hw_addr_random(struct net_device *dev)
> */
> static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2)
> {
> +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
> + u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2));
> + fold |= ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4)));
> +
> + BUILD_BUG_ON(ETH_ALEN != 6);
> + return fold != 0;
> +#else
> const u16 *a = (const u16 *) addr1;
> const u16 *b = (const u16 *) addr2;
>
> BUILD_BUG_ON(ETH_ALEN != 6);
> return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
> +#endif
> }
>
If you really want to be efficient do it as one 64 bit mask and compare.
^ permalink raw reply
* Re: [PATCH 0/7] Drop support for Renesys H8/300 architecture
From: Guenter Roeck @ 2013-08-31 13:56 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Yoshinori Sato, Linus Torvalds, Wim Van Sebroeck,
Linux Kernel Mailing List, IDE-ML, Network Development,
Linux Watchdog Mailing List, David S. Miller, Al Viro, Eric Paris,
Greg Kroah-Hartman, Jiang Liu, David Howells, Thomas Gleixner,
Stephen Rothwell
In-Reply-To: <CAMuHMdW6KcHbpR_KzbTg9V_FJ8XvQAWQOB-2jXQxG5fo1wWg1A@mail.gmail.com>
On 08/30/2013 11:44 PM, Geert Uytterhoeven wrote:
> On Fri, Aug 30, 2013 at 9:37 PM, Guenter Roeck <linux@roeck-us.net> wrote:
>> On Fri, Aug 30, 2013 at 12:14:20PM -0700, Linus Torvalds wrote:
>>> On Fri, Aug 30, 2013 at 12:11 PM, Guenter Roeck <linux@roeck-us.net> wrote:
>>>>
>>>> I would not mind if Linus would agree to pull it right away for 3.12,
>>>> but that seems to be a bit on the fast side.
>>>
>>> I'm ok with code deletion patches, I don't think that would be a
>>> problem. I didn't check them, but I assume this is all literally just
>>> removing code that is conditional on h8/300 config options?
>>>
>> Yes.
>>
>> I found a couple more since I sent the series, but nothing significant.
>>
>> What is your preference - keep it until 3.13, or prepare it now and send you
>> a pull request for 3.12 ?
>
> It would be nice to check with Sato-san, who wanted to attend Kernel
> Summit as a hobbyist architecture maintainer, and see what are his plans
> and opinions.
>
Yes, of course. My bad that my send script dropped him of all people from the
original e-mail :(. I fixed that in version 2.
Guenter
^ permalink raw reply
* Re: [-next] openvswitch BUILD_BUG_ON failed
From: Geert Uytterhoeven @ 2013-08-31 12:11 UTC (permalink / raw)
To: Jesse Gross
Cc: David Miller, Andy Zhou, dev@openvswitch.org, netdev,
Linux Kernel Mailing List, Linux-Next
In-Reply-To: <CAEP_g=-XxgK9HVxvcaW3RS2zfa+77pB4cqfLFC0rcV7QJc+2BQ@mail.gmail.com>
On Fri, Aug 30, 2013 at 3:11 AM, Jesse Gross <jesse@nicira.com> wrote:
> On Thu, Aug 29, 2013 at 3:10 PM, David Miller <davem@davemloft.net> wrote:
>> From: Jesse Gross <jesse@nicira.com>
>> Date: Thu, 29 Aug 2013 14:42:22 -0700
>>
>>> On Thu, Aug 29, 2013 at 2:21 PM, Geert Uytterhoeven
>>> <geert@linux-m68k.org> wrote:
>>>> However, I have some doubts about other alignment "enforcements":
>>>>
>>>> "__aligned(__alignof__(long))" makes the whole struct aligned to the
>>>> alignment rule for "long":
>>>> 1. This is only 2 bytes on m68k, i.e. != sizeof(long).
>>>> 2. This is 4 bytes on many 32-bit platforms, which may be less than the
>>>> default alignment for "__be64" (cfr. some members of struct
>>>> ovs_key_ipv4_tunnel), so this may make those 64-bit members unaligned.
>>>
>>> Do any of those 32-bit architectures actually care about alignment of
>>> 64 bit values? On 32-bit x86, a long is 32 bits but the alignment
>>> requirement of __be64 is also 32 bit.
>>
>> All except x86-32 do, it is in fact the odd man out with respect to this
>> issue.
>
> Thanks, good to know.
>
> Andy, do you want to modify your patch to just drop the alignment
> specification as Geert suggested (but definitely keep the new build
> assert that you added)? It's probably better to just send the patch to
> netdev (against net-next) as well since you'll likely get better
> comments there and we can fix this faster if you cut out the
> middleman.
Why do you want to keep the build asserts?
Is this in-memory structure also transfered as-is over the network?
If yes, you definitely want the padding.
Nevertheless, as the struct contains u32 and even __be64 members, the
size of the struct will always be a multiple of the alignment unit for
64-bit quantities (and thus also for long), as per the C standard.
Hence the check
BUILD_BUG_ON(sizeof(struct sw_flow_key) % __alignof__(long));
will only catch bad compiler bugs or people adding __packed to the struct.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Realtek r8168 hangs when sending data at full speed on a gigabit link
From: Frédéric Leroy @ 2013-08-31 10:15 UTC (permalink / raw)
To: netdev; +Cc: Realtek linux nic maintainers, Francois Romieu
Hello,
My network card hangs when I send data at full speed on a gigabit link.
This is a realtek :
[fredo:~/work/r8169] $ lspci | grep Realtek
02:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd.
RTL8111/8168 PCI Express Gigabit Ethernet controller (rev 09)
[fredo:~/work/r8169] $ dmesg | grep r8169
[ 1.732159] r8169 Gigabit Ethernet driver 2.3LK-NAPI loaded
[ 1.732376] r8169 0000:02:00.0: irq 89 for MSI/MSI-X
[ 1.732635] r8169 0000:02:00.0 eth0: RTL8168f/8111f at
0xffffc9000066a000, 60:a4:4c:5a:db:cf, XID 08000800 IRQ 89
[ 1.732639] r8169 0000:02:00.0 eth0: jumbo features [frames:
9200 bytes, tx checksumming: ko]
[ 8.400499] r8169 0000:02:00.0 eth0: link down
[ 8.400520] r8169 0000:02:00.0 eth0: link down
[ 11.218946] r8169 0000:02:00.0 eth0: link up
I tried several kernel, up to 3.11.0-rc7+ and found that 3.1.0 works,
but bisecting the kernel gives me random result, depending on my "bad"
start point :
262eb9b2237ecee047451a636e799ea1572b685a cfg80211: split
wext compatibility to separate header
7af40ad909e3e92a1cbb728999c427d2fa3b381d igb: push data
into first igb_tx_buffer sooner to reduce stack usage
f53b170f465d52546c33faa962c3d2609a6bf5b3 brcm80211:
removed unused functions
The only clue I have is the IO_PAGE_FAULT in the kernel logs :
Aug 26 09:46:17 devel kernel: [ 0.000000] Linux version
3.8.0-29-generic (buildd@roseapple) (gcc version 4.7.3 (Ubuntu/Linaro
4.7.3-1ubuntu1) ) #42-Ubuntu SMP Tue Aug 13 19:40:39 UTC 2013 (Ubuntu
3.8.0-29.42-generic 3.8.13.5)
Aug 26 09:49:13 devel kernel: [ 184.973716] AMD-Vi: Event
logged [IO_PAGE_FAULT device=02:00.0 domain=0x0015
address=0x0000000000003000 flags=0x0050]
Aug 26 09:49:43 devel kernel: [ 214.970724] ------------[ cut
here ]------------
Aug 26 09:49:43 devel kernel: [ 214.970731] WARNING: at
/build/buildd/linux-3.8.0/net/sched/sch_generic.c:254
dev_watchdog+0x242/0x250()
Aug 26 09:49:43 devel kernel: [ 214.970732] Hardware name: To
be filled by O.E.M.
Aug 26 09:49:43 devel kernel: [ 214.970733] NETDEV WATCHDOG:
eth0 (r8169): transmit queue 0 timed out
Aug 26 09:49:43 devel kernel: [ 214.970734] Modules linked in:
nls_iso8859_1(F) usb_storage(F) arc4(F) md4(F) nls_utf8 cifs(F)
fscache(F) pci_stub vboxpci(OF) vboxnetadp(OF) vboxnetflt(OF)
vboxdrv(OF) rfcomm parport_pc(F) ppdev(F) bnep bluetooth binfmt_misc(F)
e4000 snd_hda_codec_hdmi rtl2832 ext2(F) dvb_usb_rtl28xxu rtl2830
dvb_usb_v2 dvb_core rc_core usblp kvm_amd eeepc_wmi joydev(F) asus_wmi
kvm sparse_keymap video(F) mxm_wmi ghash_clmulni_intel(F) aesni_intel(F)
aes_x86_64(F) xts(F) lrw(F) gf128mul(F) snd_hda_codec_realtek
ablk_helper(F) cryptd(F) microcode(F) snd_hda_intel snd_seq_midi(F)
radeon snd_hda_codec snd_seq_midi_event(F) snd_hwdep(F) snd_pcm(F)
snd_rawmidi(F) fam15h_power serio_raw(F) sp5100_tco snd_page_alloc(F)
snd_seq(F) snd_seq_device(F) k10temp ttm i2c_piix4 edac_core
snd_timer(F) edac_mce_amd drm_kms_helper drm snd(F) i2c_algo_bit wmi
soundcore(F) mac_hid lp(F) parport(F) hid_logitech_dj hid_generic usbhid
hid skge r8169 ahci(F) libahci(F)
Aug 26 09:49:43 devel kernel: [ 214.970774] Pid: 0, comm:
swapper/4 Tainted: GF O 3.8.0-29-generic #42-Ubuntu
Aug 26 09:49:43 devel kernel: [ 214.970776] Call Trace:
Aug 26 09:49:43 devel kernel: [ 214.970777] <IRQ>
[<ffffffff810589bf>] warn_slowpath_common+0x7f/0xc0
Aug 26 09:49:43 devel kernel: [ 214.970782]
[<ffffffff81058abc>] warn_slowpath_fmt+0x4c/0x50
Aug 26 09:49:43 devel kernel: [ 214.970785]
[<ffffffff81074e84>] ? insert_work+0x94/0xb0
Aug 26 09:49:43 devel kernel: [ 214.970789]
[<ffffffff815e8922>] dev_watchdog+0x242/0x250
Aug 26 09:49:43 devel kernel: [ 214.970791]
[<ffffffff815e86e0>] ? dev_graft_qdisc+0x90/0x90
Aug 26 09:49:43 devel kernel: [ 214.970793]
[<ffffffff810682a6>] call_timer_fn+0x36/0x110
Aug 26 09:49:43 devel kernel: [ 214.970795]
[<ffffffff815e86e0>] ? dev_graft_qdisc+0x90/0x90
Aug 26 09:49:43 devel kernel: [ 214.970797]
[<ffffffff81069ed6>] run_timer_softirq+0x1f6/0x2a0
Aug 26 09:49:43 devel kernel: [ 214.970800]
[<ffffffff8106110f>] __do_softirq+0xcf/0x200
Aug 26 09:49:43 devel kernel: [ 214.970803]
[<ffffffff81574150>] ? centrino_target+0x370/0x370
Aug 26 09:49:43 devel kernel: [ 214.970805]
[<ffffffff816d6a9c>] call_softirq+0x1c/0x30
Aug 26 09:49:43 devel kernel: [ 214.970808]
[<ffffffff81016555>] do_softirq+0x75/0xb0
Aug 26 09:49:43 devel kernel: [ 214.970810]
[<ffffffff810613a5>] irq_exit+0xa5/0xb0
Aug 26 09:49:43 devel kernel: [ 214.970812]
[<ffffffff816d741e>] smp_apic_timer_interrupt+0x6e/0x99
Aug 26 09:49:43 devel kernel: [ 214.970814]
[<ffffffff816d635d>] apic_timer_interrupt+0x6d/0x80
Aug 26 09:49:43 devel kernel: [ 214.970815] <EOI>
[<ffffffff81091a4d>] ? sched_clock_cpu+0xbd/0x110
Aug 26 09:49:43 devel kernel: [ 214.970819]
[<ffffffff81574b98>] ? cpuidle_wrap_enter+0x58/0xa0
Aug 26 09:49:43 devel kernel: [ 214.970821]
[<ffffffff81574bf0>] cpuidle_enter_tk+0x10/0x20
Aug 26 09:49:43 devel kernel: [ 214.970823]
[<ffffffff815747e5>] cpuidle_idle_call+0xa5/0x260
Aug 26 09:49:43 devel kernel: [ 214.970826]
[<ffffffff8101d5af>] cpu_idle+0xaf/0x120
Aug 26 09:49:43 devel kernel: [ 214.970828]
[<ffffffff816b6a83>] start_secondary+0x1e0/0x1e5
Aug 26 09:49:43 devel kernel: [ 214.970830] ---[ end trace
9135f3ab0912c9e0 ]---
Aug 26 09:49:43 devel kernel: [ 214.977428] r8169 0000:02:00.0
eth0: link up
For triggering the bug, I use iperf, which either works, or hangs almost
immediately
with multiple threads :
iperf -c myiperfserver -P 3 -t 60
Could you help me to fix this ?
Best regards,
--
Frederic Leroy
^ permalink raw reply
* Re: [PATCH net-next] tcp: Change return value of tcp_rcv_established()
From: Daniel Borkmann @ 2013-08-31 9:28 UTC (permalink / raw)
To: Vijay Subramanian; +Cc: netdev, davem, eric.dumazet
In-Reply-To: <1377842617-663-1-git-send-email-subramanian.vijay@gmail.com>
On 08/30/2013 08:03 AM, Vijay Subramanian wrote:
> tcp_rcv_established() returns only one value namely 0. We change the return
> value to void (as suggested by David Miller).
>
> After commit 0c24604b (tcp: implement RFC 5961 4.2), we no longer send RSTs in
> response to SYNs. We can remove the check and processing on the return value of
> tcp_rcv_established().
>
> We also fix jtcp_rcv_established() in tcp_probe.c to match that of
> tcp_rcv_established().
>
> Signed-off-by: Vijay Subramanian <subramanian.vijay@gmail.com>
> ---
> Changes: Earlier patch titled "tcp: Remove needless check of return value"
> fixed only the second issue above.
>
[...]
>
> csum_error:
> TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_CSUMERRORS);
> @@ -5260,7 +5260,7 @@ csum_error:
>
> discard:
> __kfree_skb(skb);
> - return 0;
> + return;
> }
> EXPORT_SYMBOL(tcp_rcv_established);
You can remove this return here in discard case.
[...]
> diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
> index 622a437..8b10379 100644
> --- a/net/ipv4/tcp_probe.c
> +++ b/net/ipv4/tcp_probe.c
> @@ -122,7 +122,7 @@ static inline int tcp_probe_avail(void)
> * Hook inserted to be called before each receive packet.
> * Note: arguments must match tcp_rcv_established()!
> */
> -static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
> +static void jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
> const struct tcphdr *th, unsigned int len)
Also, you should align the second line here to match opening '('.
> {
> const struct tcp_sock *tp = tcp_sk(sk);
> @@ -172,7 +172,7 @@ static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
> }
>
> jprobe_return();
> - return 0;
> + return;
This return can then be removed if it's void anyway.
> }
>
[...]
^ permalink raw reply
* [PATCH net-next] etherdevice: Optimize compare_ether_addr/ether_addr_equal
From: Joe Perches @ 2013-08-31 8:54 UTC (permalink / raw)
To: David Miller; +Cc: Eric Dumazet, netdev
When CONFIG_HAS_EFFICIENT_UNALIGNED_ACCESS is set,
optimize compare_ether_addr a little by removing an
xor and or by using a u32 and u16 comparison
instead of 3 separate u16 comparisons.
Make the ether_addr_equal_64bits code a bit simpler
by adding a test for CONFIG_64BIT and calling
ether_addr_equal otherwise.
This also slightly improves ether_addr_equal_64bits
by removing the zap_last_2bytes shifts in the !64bit
case.
Signed-off-by: Joe Perches <joe@perches.com>
---
include/linux/etherdevice.h | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index c623861..2514d17 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -208,11 +208,19 @@ static inline void eth_hw_addr_random(struct net_device *dev)
*/
static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2)
{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+ u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2));
+ fold |= ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4)));
+
+ BUILD_BUG_ON(ETH_ALEN != 6);
+ return fold != 0;
+#else
const u16 *a = (const u16 *) addr1;
const u16 *b = (const u16 *) addr2;
BUILD_BUG_ON(ETH_ALEN != 6);
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0;
+#endif
}
/**
@@ -253,16 +261,11 @@ static inline unsigned long zap_last_2bytes(unsigned long value)
static inline bool ether_addr_equal_64bits(const u8 addr1[6+2],
const u8 addr2[6+2])
{
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(CONFIG_64BIT)
unsigned long fold = ((*(unsigned long *)addr1) ^
(*(unsigned long *)addr2));
- if (sizeof(fold) == 8)
- return zap_last_2bytes(fold) == 0;
-
- fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^
- (*(unsigned long *)(addr2 + 4)));
- return fold == 0;
+ return zap_last_2bytes(fold) == 0;
#else
return ether_addr_equal(addr1, addr2);
#endif
^ permalink raw reply related
* Re: Fwd: RFC 6980 on Security Implications of IPv6 Fragmentation with IPv6 Neighbor Discovery
From: Fernando Gont @ 2013-08-31 5:22 UTC (permalink / raw)
To: Loganaden Velvindron, netdev
In-Reply-To: <20130815102507.GA24122@order.stressinduktion.org>
On 08/15/2013 07:25 AM, Hannes Frederic Sowa wrote:
>
>> 3) What will/could break with this diff in a production environment ?
>
> RA messages could get fragmented if a speaker puts lots of options in it. I
> hope all RA speakers already spread the options over multiple RAs, but I don't
> know. In case the RA is fragmented it will now be dropped silently.
My understanding is that some implementations were already dropping
fragmented RAs... so you better avoid fragmentation. Put another way:
you're already in trouble if you rely on fragmented ND messages.
Cheers,
--
Fernando Gont
e-mail: fernando@gont.com.ar || fgont@si6networks.com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1
^ permalink raw reply
* Re: Fwd: RFC 6980 on Security Implications of IPv6 Fragmentation with IPv6 Neighbor Discovery
From: Fernando Gont @ 2013-08-31 5:20 UTC (permalink / raw)
To: Loganaden Velvindron; +Cc: netdev
In-Reply-To: <CAOp4FwSatwRtx_O4Aio4e0HmahxdwiY9JToc8E+1rMT9oCjLrA@mail.gmail.com>
On 08/15/2013 07:12 AM, Loganaden Velvindron wrote:
>
>
> I'm not sure if you got my previous mails, but I'd like to know a couple
> of things:
>
> 1) How can I test this diff ?
Use the -y (fragmentation) option with the ns6, na6, r6, ra6, and rd6
tools of the IPv6 toolkit (http://www.si6networks.com/tools/ipv6toolkit)
-- there are are examples in the manpages.
Cheers,
--
Fernando Gont
e-mail: fernando@gont.com.ar || fgont@si6networks.com
PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1
^ permalink raw reply
* Re: [PATCH 0/7] Drop support for Renesys H8/300 architecture
From: Geert Uytterhoeven @ 2013-08-31 6:44 UTC (permalink / raw)
To: Guenter Roeck, Yoshinori Sato
Cc: Linus Torvalds, Wim Van Sebroeck, Linux Kernel Mailing List,
IDE-ML, Network Development, Linux Watchdog Mailing List,
David S. Miller, Al Viro, Eric Paris, Greg Kroah-Hartman,
Jiang Liu, David Howells, Thomas Gleixner, Stephen Rothwell
In-Reply-To: <20130830193740.GA13101@roeck-us.net>
On Fri, Aug 30, 2013 at 9:37 PM, Guenter Roeck <linux@roeck-us.net> wrote:
> On Fri, Aug 30, 2013 at 12:14:20PM -0700, Linus Torvalds wrote:
>> On Fri, Aug 30, 2013 at 12:11 PM, Guenter Roeck <linux@roeck-us.net> wrote:
>> >
>> > I would not mind if Linus would agree to pull it right away for 3.12,
>> > but that seems to be a bit on the fast side.
>>
>> I'm ok with code deletion patches, I don't think that would be a
>> problem. I didn't check them, but I assume this is all literally just
>> removing code that is conditional on h8/300 config options?
>>
> Yes.
>
> I found a couple more since I sent the series, but nothing significant.
>
> What is your preference - keep it until 3.13, or prepare it now and send you
> a pull request for 3.12 ?
It would be nice to check with Sato-san, who wanted to attend Kernel
Summit as a hobbyist architecture maintainer, and see what are his plans
and opinions.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: ipv4: warnings on sk_wmem_queued
From: Eric Wong @ 2013-08-31 6:44 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel
In-Reply-To: <20130830195638.GA27393@dcvr.yhbt.net>
Eric Wong <normalperson@yhbt.net> wrote:
> I noticed these warnings on stock 3.10.9 running stress tests on
> cmogstored.git (git://bogomips.org/cmogstored.git) doing standard
> HTTP server stuff between lo and tmpfs:
I'm still running the same test (in-place upgraded cmogstored a few
times to fix some bugs), and haven't hit these warnings again
(constantly pushing around 20GB/s total).
I forget to mention cmogstored is multithreaded and idle clients
automatically migrate between threads when becoming active (using
EPOLLONESHOT), so maybe this tickles some rare race condition
somewhere...
> Aug 30 06:03:54 localhost kernel: WARNING: at net/core/stream.c:200 sk_stream_kill_queues+0x131/0x140()
<snip>
> Aug 30 06:03:54 localhost kernel: WARNING: at net/ipv4/af_inet.c:155 inet_sock_destruct+0x191/0x1e0()
I probably won't be in a good position to reboot/test patches until
Tuesday, though.
^ permalink raw reply
* Re: [ovs-dev] [RFC PATCH net-next 1/4] iptunnels: remove net arg from iptunnel_xmit()
From: Pravin Shelar @ 2013-08-31 6:09 UTC (permalink / raw)
To: Nicolas Dichtel; +Cc: netdev, dev@openvswitch.org, David Miller
In-Reply-To: <1377703210-7021-2-git-send-email-nicolas.dichtel@6wind.com>
On Wed, Aug 28, 2013 at 8:20 AM, Nicolas Dichtel
<nicolas.dichtel@6wind.com> wrote:
> This argument is not used, let's remove it.
>
> Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
> ---
> drivers/net/vxlan.c | 3 +--
> include/net/ip_tunnels.h | 3 +--
> net/ipv4/ip_tunnel.c | 3 +--
> net/ipv4/ip_tunnel_core.c | 3 +--
> net/ipv6/sit.c | 4 ++--
> net/openvswitch/vport-gre.c | 2 +-
> 6 files changed, 7 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
> index 3b21aca0c0c2..3bc27c2ca569 100644
> --- a/drivers/net/vxlan.c
> +++ b/drivers/net/vxlan.c
> @@ -1171,8 +1171,7 @@ int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
> if (err)
> return err;
>
> - return iptunnel_xmit(net, rt, skb, src, dst,
> - IPPROTO_UDP, tos, ttl, df);
> + return iptunnel_xmit(rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df);
Can you remove argument `net` from vxlan_xmit_skb() also?
Thanks.
^ permalink raw reply
* Re: [PATCH net-next v11 01/11] ipv6: move ip6_dst_hoplimit() into core kernel
From: David Miller @ 2013-08-31 5:56 UTC (permalink / raw)
To: amwang; +Cc: netdev, eric.dumazet
In-Reply-To: <1377925654.29366.1.camel@cr0>
From: Cong Wang <amwang@redhat.com>
Date: Sat, 31 Aug 2013 13:07:34 +0800
> On Sat, 2013-08-31 at 00:59 -0400, David Miller wrote:
>> From: Cong Wang <amwang@redhat.com>
>> Date: Sat, 31 Aug 2013 11:07:18 +0800
>>
>> > @@ -75,3 +76,24 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
>> > return offset;
>> > }
>> > EXPORT_SYMBOL(ip6_find_1stfragopt);
>> > +
>> > +#if IS_ENABLED(CONFIG_IPV6)
>> > +int ip6_dst_hoplimit(struct dst_entry *dst)
>> ...
>> > +#endif
>> > +EXPORT_SYMBOL(ip6_dst_hoplimit);
>>
>> I don't think the export should be outside of the #if region.
>>
>> Did you test the build with IPV6 disabled?
>
> Yes, but it didn't show me any error.
Weird, please correct this anyways.
Thanks.
^ permalink raw reply
* [PATCH net-next v12 06/11] vxlan: add ipv6 support
From: Cong Wang @ 2013-08-31 5:44 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, David Stevens, Stephen Hemminger, Cong Wang
In-Reply-To: <1377927878-23975-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
This patch adds IPv6 support to vxlan device, as the new version
RFC already mentions it:
http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-03
Cc: David Stevens <dlstevens@us.ibm.com>
Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
drivers/net/vxlan.c | 764 +++++++++++++++++++++++++++++++++--------
include/net/vxlan.h | 2 +-
include/uapi/linux/if_link.h | 2 +
net/openvswitch/vport-vxlan.c | 2 +-
4 files changed, 622 insertions(+), 148 deletions(-)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 3b21aca..faf131e 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -6,9 +6,6 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * TODO
- * - IPv6 (not in RFC)
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -43,6 +40,11 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/vxlan.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ipv6.h>
+#include <net/addrconf.h>
+#include <net/ip6_tunnel.h>
+#endif
#define VXLAN_VERSION "0.1"
@@ -59,6 +61,8 @@
#define VXLAN_VID_MASK (VXLAN_N_VID - 1)
/* IP header + UDP + VXLAN + Ethernet header */
#define VXLAN_HEADROOM (20 + 8 + 8 + 14)
+/* IPv6 header + UDP + VXLAN + Ethernet header */
+#define VXLAN6_HEADROOM (40 + 8 + 8 + 14)
#define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
@@ -92,8 +96,14 @@ struct vxlan_net {
spinlock_t sock_lock;
};
+union vxlan_addr {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr sa;
+};
+
struct vxlan_rdst {
- __be32 remote_ip;
+ union vxlan_addr remote_ip;
__be16 remote_port;
u32 remote_vni;
u32 remote_ifindex;
@@ -120,7 +130,7 @@ struct vxlan_dev {
struct vxlan_sock *vn_sock; /* listening socket */
struct net_device *dev;
struct vxlan_rdst default_dst; /* default destination */
- __be32 saddr; /* source address */
+ union vxlan_addr saddr; /* source address */
__be16 dst_port;
__u16 port_min; /* source port range */
__u16 port_max;
@@ -146,6 +156,7 @@ struct vxlan_dev {
#define VXLAN_F_RSC 0x04
#define VXLAN_F_L2MISS 0x08
#define VXLAN_F_L3MISS 0x10
+#define VXLAN_F_IPV6 0x20 /* internal flag */
/* salt for hash table */
static u32 vxlan_salt __read_mostly;
@@ -153,6 +164,96 @@ static struct workqueue_struct *vxlan_wq;
static void vxlan_sock_work(struct work_struct *work);
+#if IS_ENABLED(CONFIG_IPV6)
+static inline
+bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
+{
+ if (a->sa.sa_family != b->sa.sa_family)
+ return false;
+ if (a->sa.sa_family == AF_INET6)
+ return ipv6_addr_equal(&a->sin6.sin6_addr, &b->sin6.sin6_addr);
+ else
+ return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
+}
+
+static inline bool vxlan_addr_any(const union vxlan_addr *ipa)
+{
+ if (ipa->sa.sa_family == AF_INET6)
+ return ipv6_addr_any(&ipa->sin6.sin6_addr);
+ else
+ return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY);
+}
+
+static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa)
+{
+ if (ipa->sa.sa_family == AF_INET6)
+ return ipv6_addr_is_multicast(&ipa->sin6.sin6_addr);
+ else
+ return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr));
+}
+
+static int vxlan_nla_get_addr(union vxlan_addr *ip, struct nlattr *nla)
+{
+ if (nla_len(nla) >= sizeof(struct in6_addr)) {
+ nla_memcpy(&ip->sin6.sin6_addr, nla, sizeof(struct in6_addr));
+ ip->sa.sa_family = AF_INET6;
+ return 0;
+ } else if (nla_len(nla) >= sizeof(__be32)) {
+ ip->sin.sin_addr.s_addr = nla_get_be32(nla);
+ ip->sa.sa_family = AF_INET;
+ return 0;
+ } else {
+ return -EAFNOSUPPORT;
+ }
+}
+
+static int vxlan_nla_put_addr(struct sk_buff *skb, int attr,
+ const union vxlan_addr *ip)
+{
+ if (ip->sa.sa_family == AF_INET6)
+ return nla_put(skb, attr, sizeof(struct in6_addr), &ip->sin6.sin6_addr);
+ else
+ return nla_put_be32(skb, attr, ip->sin.sin_addr.s_addr);
+}
+
+#else /* !CONFIG_IPV6 */
+
+static inline
+bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
+{
+ return a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr;
+}
+
+static inline bool vxlan_addr_any(const union vxlan_addr *ipa)
+{
+ return ipa->sin.sin_addr.s_addr == htonl(INADDR_ANY);
+}
+
+static inline bool vxlan_addr_multicast(const union vxlan_addr *ipa)
+{
+ return IN_MULTICAST(ntohl(ipa->sin.sin_addr.s_addr));
+}
+
+static int vxlan_nla_get_addr(union vxlan_addr *ip, struct nlattr *nla)
+{
+ if (nla_len(nla) >= sizeof(struct in6_addr)) {
+ return -EAFNOSUPPORT;
+ } else if (nla_len(nla) >= sizeof(__be32)) {
+ ip->sin.sin_addr.s_addr = nla_get_be32(nla);
+ ip->sa.sa_family = AF_INET;
+ return 0;
+ } else {
+ return -EAFNOSUPPORT;
+ }
+}
+
+static int vxlan_nla_put_addr(struct sk_buff *skb, int attr,
+ const union vxlan_addr *ip)
+{
+ return nla_put_be32(skb, attr, ip->sin.sin_addr.s_addr);
+}
+#endif
+
/* Virtual Network hash table head */
static inline struct hlist_head *vni_head(struct vxlan_sock *vs, u32 id)
{
@@ -239,7 +340,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
if (type == RTM_GETNEIGH) {
ndm->ndm_family = AF_INET;
- send_ip = rdst->remote_ip != htonl(INADDR_ANY);
+ send_ip = !vxlan_addr_any(&rdst->remote_ip);
send_eth = !is_zero_ether_addr(fdb->eth_addr);
} else
ndm->ndm_family = AF_BRIDGE;
@@ -251,7 +352,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr))
goto nla_put_failure;
- if (send_ip && nla_put_be32(skb, NDA_DST, rdst->remote_ip))
+ if (send_ip && vxlan_nla_put_addr(skb, NDA_DST, &rdst->remote_ip))
goto nla_put_failure;
if (rdst->remote_port && rdst->remote_port != vxlan->dst_port &&
@@ -283,7 +384,7 @@ static inline size_t vxlan_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct ndmsg))
+ nla_total_size(ETH_ALEN) /* NDA_LLADDR */
- + nla_total_size(sizeof(__be32)) /* NDA_DST */
+ + nla_total_size(sizeof(struct in6_addr)) /* NDA_DST */
+ nla_total_size(sizeof(__be16)) /* NDA_PORT */
+ nla_total_size(sizeof(__be32)) /* NDA_VNI */
+ nla_total_size(sizeof(__u32)) /* NDA_IFINDEX */
@@ -317,14 +418,14 @@ errout:
rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
}
-static void vxlan_ip_miss(struct net_device *dev, __be32 ipa)
+static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_fdb f = {
.state = NUD_STALE,
};
struct vxlan_rdst remote = {
- .remote_ip = ipa, /* goes to NDA_DST */
+ .remote_ip = *ipa, /* goes to NDA_DST */
.remote_vni = VXLAN_N_VID,
};
@@ -397,13 +498,13 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
/* caller should hold vxlan->hash_lock */
static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
- __be32 ip, __be16 port,
+ union vxlan_addr *ip, __be16 port,
__u32 vni, __u32 ifindex)
{
struct vxlan_rdst *rd;
list_for_each_entry(rd, &f->remotes, list) {
- if (rd->remote_ip == ip &&
+ if (vxlan_addr_equal(&rd->remote_ip, ip) &&
rd->remote_port == port &&
rd->remote_vni == vni &&
rd->remote_ifindex == ifindex)
@@ -415,7 +516,7 @@ static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
/* Replace destination of unicast mac */
static int vxlan_fdb_replace(struct vxlan_fdb *f,
- __be32 ip, __be16 port, __u32 vni, __u32 ifindex)
+ union vxlan_addr *ip, __be16 port, __u32 vni, __u32 ifindex)
{
struct vxlan_rdst *rd;
@@ -426,7 +527,7 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
rd = list_first_entry_or_null(&f->remotes, struct vxlan_rdst, list);
if (!rd)
return 0;
- rd->remote_ip = ip;
+ rd->remote_ip = *ip;
rd->remote_port = port;
rd->remote_vni = vni;
rd->remote_ifindex = ifindex;
@@ -435,7 +536,7 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
/* Add/update destinations for multicast */
static int vxlan_fdb_append(struct vxlan_fdb *f,
- __be32 ip, __be16 port, __u32 vni, __u32 ifindex)
+ union vxlan_addr *ip, __be16 port, __u32 vni, __u32 ifindex)
{
struct vxlan_rdst *rd;
@@ -446,7 +547,7 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
rd = kmalloc(sizeof(*rd), GFP_ATOMIC);
if (rd == NULL)
return -ENOBUFS;
- rd->remote_ip = ip;
+ rd->remote_ip = *ip;
rd->remote_port = port;
rd->remote_vni = vni;
rd->remote_ifindex = ifindex;
@@ -458,7 +559,7 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
/* Add new entry to forwarding table -- assumes lock held */
static int vxlan_fdb_create(struct vxlan_dev *vxlan,
- const u8 *mac, __be32 ip,
+ const u8 *mac, union vxlan_addr *ip,
__u16 state, __u16 flags,
__be16 port, __u32 vni, __u32 ifindex,
__u8 ndm_flags)
@@ -517,7 +618,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
(is_multicast_ether_addr(mac) || is_zero_ether_addr(mac)))
return -EOPNOTSUPP;
- netdev_dbg(vxlan->dev, "add %pM -> %pI4\n", mac, &ip);
+ netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip);
f = kmalloc(sizeof(*f), GFP_ATOMIC);
if (!f)
return -ENOMEM;
@@ -565,17 +666,26 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f)
}
static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
- __be32 *ip, __be16 *port, u32 *vni, u32 *ifindex)
+ union vxlan_addr *ip, __be16 *port, u32 *vni, u32 *ifindex)
{
struct net *net = dev_net(vxlan->dev);
+ int err;
if (tb[NDA_DST]) {
- if (nla_len(tb[NDA_DST]) != sizeof(__be32))
- return -EAFNOSUPPORT;
-
- *ip = nla_get_be32(tb[NDA_DST]);
+ err = vxlan_nla_get_addr(ip, tb[NDA_DST]);
+ if (err)
+ return err;
} else {
- *ip = htonl(INADDR_ANY);
+ union vxlan_addr *remote = &vxlan->default_dst.remote_ip;
+ if (remote->sa.sa_family == AF_INET) {
+ ip->sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ ip->sa.sa_family = AF_INET;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ ip->sin6.sin6_addr = in6addr_any;
+ ip->sa.sa_family = AF_INET6;
+#endif
+ }
}
if (tb[NDA_PORT]) {
@@ -618,7 +728,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
{
struct vxlan_dev *vxlan = netdev_priv(dev);
/* struct net *net = dev_net(vxlan->dev); */
- __be32 ip;
+ union vxlan_addr ip;
__be16 port;
u32 vni, ifindex;
int err;
@@ -637,7 +747,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return err;
spin_lock_bh(&vxlan->hash_lock);
- err = vxlan_fdb_create(vxlan, addr, ip, ndm->ndm_state, flags,
+ err = vxlan_fdb_create(vxlan, addr, &ip, ndm->ndm_state, flags,
port, vni, ifindex, ndm->ndm_flags);
spin_unlock_bh(&vxlan->hash_lock);
@@ -652,7 +762,7 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_fdb *f;
struct vxlan_rdst *rd = NULL;
- __be32 ip;
+ union vxlan_addr ip;
__be16 port;
u32 vni, ifindex;
int err;
@@ -668,8 +778,8 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
if (!f)
goto out;
- if (ip != htonl(INADDR_ANY)) {
- rd = vxlan_fdb_find_rdst(f, ip, port, vni, ifindex);
+ if (!vxlan_addr_any(&ip)) {
+ rd = vxlan_fdb_find_rdst(f, &ip, port, vni, ifindex);
if (!rd)
goto out;
}
@@ -732,7 +842,7 @@ out:
* Return true if packet is bogus and should be droppped.
*/
static bool vxlan_snoop(struct net_device *dev,
- __be32 src_ip, const u8 *src_mac)
+ union vxlan_addr *src_ip, const u8 *src_mac)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_fdb *f;
@@ -741,7 +851,7 @@ static bool vxlan_snoop(struct net_device *dev,
if (likely(f)) {
struct vxlan_rdst *rdst = first_remote_rcu(f);
- if (likely(rdst->remote_ip == src_ip))
+ if (likely(vxlan_addr_equal(&rdst->remote_ip, src_ip)))
return false;
/* Don't migrate static entries, drop packets */
@@ -750,10 +860,10 @@ static bool vxlan_snoop(struct net_device *dev,
if (net_ratelimit())
netdev_info(dev,
- "%pM migrated from %pI4 to %pI4\n",
+ "%pM migrated from %pIS to %pIS\n",
src_mac, &rdst->remote_ip, &src_ip);
- rdst->remote_ip = src_ip;
+ rdst->remote_ip = *src_ip;
f->updated = jiffies;
vxlan_fdb_notify(vxlan, f, RTM_NEWNEIGH);
} else {
@@ -775,7 +885,7 @@ static bool vxlan_snoop(struct net_device *dev,
}
/* See if multicast group is already in use by other ID */
-static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip)
+static bool vxlan_group_used(struct vxlan_net *vn, union vxlan_addr *remote_ip)
{
struct vxlan_dev *vxlan;
@@ -783,7 +893,8 @@ static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip)
if (!netif_running(vxlan->dev))
continue;
- if (vxlan->default_dst.remote_ip == remote_ip)
+ if (vxlan_addr_equal(&vxlan->default_dst.remote_ip,
+ remote_ip))
return true;
}
@@ -819,13 +930,23 @@ static void vxlan_igmp_join(struct work_struct *work)
struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join);
struct vxlan_sock *vs = vxlan->vn_sock;
struct sock *sk = vs->sock->sk;
- struct ip_mreqn mreq = {
- .imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
- .imr_ifindex = vxlan->default_dst.remote_ifindex,
- };
+ union vxlan_addr *ip = &vxlan->default_dst.remote_ip;
+ int ifindex = vxlan->default_dst.remote_ifindex;
lock_sock(sk);
- ip_mc_join_group(sk, &mreq);
+ if (ip->sa.sa_family == AF_INET) {
+ struct ip_mreqn mreq = {
+ .imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr,
+ .imr_ifindex = ifindex,
+ };
+
+ ip_mc_join_group(sk, &mreq);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ ipv6_stub->ipv6_sock_mc_join(sk, ifindex,
+ &ip->sin6.sin6_addr);
+#endif
+ }
release_sock(sk);
vxlan_sock_release(vs);
@@ -838,13 +959,24 @@ static void vxlan_igmp_leave(struct work_struct *work)
struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave);
struct vxlan_sock *vs = vxlan->vn_sock;
struct sock *sk = vs->sock->sk;
- struct ip_mreqn mreq = {
- .imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
- .imr_ifindex = vxlan->default_dst.remote_ifindex,
- };
+ union vxlan_addr *ip = &vxlan->default_dst.remote_ip;
+ int ifindex = vxlan->default_dst.remote_ifindex;
lock_sock(sk);
- ip_mc_leave_group(sk, &mreq);
+ if (ip->sa.sa_family == AF_INET) {
+ struct ip_mreqn mreq = {
+ .imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr,
+ .imr_ifindex = ifindex,
+ };
+
+ ip_mc_leave_group(sk, &mreq);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ ipv6_stub->ipv6_sock_mc_drop(sk, ifindex,
+ &ip->sin6.sin6_addr);
+#endif
+ }
+
release_sock(sk);
vxlan_sock_release(vs);
@@ -896,11 +1028,14 @@ error:
static void vxlan_rcv(struct vxlan_sock *vs,
struct sk_buff *skb, __be32 vx_vni)
{
- struct iphdr *oip;
+ struct iphdr *oip = NULL;
+ struct ipv6hdr *oip6 = NULL;
struct vxlan_dev *vxlan;
struct pcpu_tstats *stats;
+ union vxlan_addr saddr;
__u32 vni;
- int err;
+ int err = 0;
+ union vxlan_addr *remote_ip;
vni = ntohl(vx_vni) >> 8;
/* Is this VNI defined? */
@@ -908,6 +1043,7 @@ static void vxlan_rcv(struct vxlan_sock *vs,
if (!vxlan)
goto drop;
+ remote_ip = &vxlan->default_dst.remote_ip;
skb_reset_mac_header(skb);
skb->protocol = eth_type_trans(skb, vxlan->dev);
@@ -917,9 +1053,20 @@ static void vxlan_rcv(struct vxlan_sock *vs,
goto drop;
/* Re-examine inner Ethernet packet */
- oip = ip_hdr(skb);
+ if (remote_ip->sa.sa_family == AF_INET) {
+ oip = ip_hdr(skb);
+ saddr.sin.sin_addr.s_addr = oip->saddr;
+ saddr.sa.sa_family = AF_INET;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ oip6 = ipv6_hdr(skb);
+ saddr.sin6.sin6_addr = oip6->saddr;
+ saddr.sa.sa_family = AF_INET6;
+#endif
+ }
+
if ((vxlan->flags & VXLAN_F_LEARN) &&
- vxlan_snoop(skb->dev, oip->saddr, eth_hdr(skb)->h_source))
+ vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source))
goto drop;
skb_reset_network_header(skb);
@@ -935,11 +1082,20 @@ static void vxlan_rcv(struct vxlan_sock *vs,
skb->encapsulation = 0;
- err = IP_ECN_decapsulate(oip, skb);
+ if (oip6)
+ err = IP6_ECN_decapsulate(oip6, skb);
+ if (oip)
+ err = IP_ECN_decapsulate(oip, skb);
+
if (unlikely(err)) {
- if (log_ecn_error)
- net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
- &oip->saddr, oip->tos);
+ if (log_ecn_error) {
+ if (oip6)
+ net_info_ratelimited("non-ECT from %pI6\n",
+ &oip6->saddr);
+ if (oip)
+ net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
+ &oip->saddr, oip->tos);
+ }
if (err > 1) {
++vxlan->dev->stats.rx_frame_errors;
++vxlan->dev->stats.rx_errors;
@@ -1009,7 +1165,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
}
f = vxlan_find_mac(vxlan, n->ha);
- if (f && first_remote_rcu(f)->remote_ip == htonl(INADDR_ANY)) {
+ if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) {
/* bridge-local neighbor */
neigh_release(n);
goto out;
@@ -1027,8 +1183,14 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
if (netif_rx_ni(reply) == NET_RX_DROP)
dev->stats.rx_dropped++;
- } else if (vxlan->flags & VXLAN_F_L3MISS)
- vxlan_ip_miss(dev, tip);
+ } else if (vxlan->flags & VXLAN_F_L3MISS) {
+ union vxlan_addr ipa = {
+ .sin.sin_addr.s_addr = tip,
+ .sa.sa_family = AF_INET,
+ };
+
+ vxlan_ip_miss(dev, &ipa);
+ }
out:
consume_skb(skb);
return NETDEV_TX_OK;
@@ -1050,6 +1212,16 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
return false;
pip = ip_hdr(skb);
n = neigh_lookup(&arp_tbl, &pip->daddr, dev);
+ if (!n && (vxlan->flags & VXLAN_F_L3MISS)) {
+ union vxlan_addr ipa = {
+ .sin.sin_addr.s_addr = pip->daddr,
+ .sa.sa_family = AF_INET,
+ };
+
+ vxlan_ip_miss(dev, &ipa);
+ return false;
+ }
+
break;
default:
return false;
@@ -1066,8 +1238,8 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
}
neigh_release(n);
return diff;
- } else if (vxlan->flags & VXLAN_F_L3MISS)
- vxlan_ip_miss(dev, pip->daddr);
+ }
+
return false;
}
@@ -1118,6 +1290,102 @@ static int handle_offloads(struct sk_buff *skb)
return 0;
}
+#if IS_ENABLED(CONFIG_IPV6)
+static int vxlan6_xmit_skb(struct net *net, struct vxlan_sock *vs,
+ struct dst_entry *dst, struct sk_buff *skb,
+ struct net_device *dev, struct in6_addr *saddr,
+ struct in6_addr *daddr, __u8 prio, __u8 ttl,
+ __be16 src_port, __be16 dst_port, __be32 vni)
+{
+ struct ipv6hdr *ip6h;
+ struct vxlanhdr *vxh;
+ struct udphdr *uh;
+ int min_headroom;
+ int err;
+
+ if (!skb->encapsulation) {
+ skb_reset_inner_headers(skb);
+ skb->encapsulation = 1;
+ }
+
+ min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len
+ + VXLAN_HLEN + sizeof(struct ipv6hdr)
+ + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
+
+ /* Need space for new headers (invalidates iph ptr) */
+ err = skb_cow_head(skb, min_headroom);
+ if (unlikely(err))
+ return err;
+
+ if (vlan_tx_tag_present(skb)) {
+ if (WARN_ON(!__vlan_put_tag(skb,
+ skb->vlan_proto,
+ vlan_tx_tag_get(skb))))
+ return -ENOMEM;
+
+ skb->vlan_tci = 0;
+ }
+
+ vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
+ vxh->vx_flags = htonl(VXLAN_FLAGS);
+ vxh->vx_vni = vni;
+
+ __skb_push(skb, sizeof(*uh));
+ skb_reset_transport_header(skb);
+ uh = udp_hdr(skb);
+
+ uh->dest = dst_port;
+ uh->source = src_port;
+
+ uh->len = htons(skb->len);
+ uh->check = 0;
+
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+ IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+ IPSKB_REROUTED);
+ skb_dst_drop(skb);
+ skb_dst_set(skb, dst);
+
+ if (!skb_is_gso(skb) && !(dst->dev->features & NETIF_F_IPV6_CSUM)) {
+ __wsum csum = skb_checksum(skb, 0, skb->len, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ uh->check = csum_ipv6_magic(saddr, daddr, skb->len,
+ IPPROTO_UDP, csum);
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+ } else {
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ uh->check = ~csum_ipv6_magic(saddr, daddr,
+ skb->len, IPPROTO_UDP, 0);
+ }
+
+ __skb_push(skb, sizeof(*ip6h));
+ skb_reset_network_header(skb);
+ ip6h = ipv6_hdr(skb);
+ ip6h->version = 6;
+ ip6h->priority = prio;
+ ip6h->flow_lbl[0] = 0;
+ ip6h->flow_lbl[1] = 0;
+ ip6h->flow_lbl[2] = 0;
+ ip6h->payload_len = htons(skb->len);
+ ip6h->nexthdr = IPPROTO_UDP;
+ ip6h->hop_limit = ttl;
+ ip6h->daddr = *daddr;
+ ip6h->saddr = *saddr;
+
+ vxlan_set_owner(vs->sock->sk, skb);
+
+ err = handle_offloads(skb);
+ if (err)
+ return err;
+
+ ip6tunnel_xmit(skb, dev);
+ return 0;
+}
+#endif
+
int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs,
struct rtable *rt, struct sk_buff *skb,
__be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
@@ -1182,15 +1450,26 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
{
struct pcpu_tstats *tx_stats = this_cpu_ptr(src_vxlan->dev->tstats);
struct pcpu_tstats *rx_stats = this_cpu_ptr(dst_vxlan->dev->tstats);
+ union vxlan_addr loopback;
+ union vxlan_addr *remote_ip = &dst_vxlan->default_dst.remote_ip;
skb->pkt_type = PACKET_HOST;
skb->encapsulation = 0;
skb->dev = dst_vxlan->dev;
__skb_pull(skb, skb_network_offset(skb));
+ if (remote_ip->sa.sa_family == AF_INET) {
+ loopback.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ loopback.sa.sa_family = AF_INET;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ loopback.sin6.sin6_addr = in6addr_loopback;
+ loopback.sa.sa_family = AF_INET6;
+#endif
+ }
+
if (dst_vxlan->flags & VXLAN_F_LEARN)
- vxlan_snoop(skb->dev, htonl(INADDR_LOOPBACK),
- eth_hdr(skb)->h_source);
+ vxlan_snoop(skb->dev, &loopback, eth_hdr(skb)->h_source);
u64_stats_update_begin(&tx_stats->syncp);
tx_stats->tx_packets++;
@@ -1211,11 +1490,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
struct vxlan_rdst *rdst, bool did_rsc)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
- struct rtable *rt;
+ struct rtable *rt = NULL;
const struct iphdr *old_iph;
struct flowi4 fl4;
- __be32 dst;
- __be16 src_port, dst_port;
+ union vxlan_addr *dst;
+ __be16 src_port = 0, dst_port;
u32 vni;
__be16 df = 0;
__u8 tos, ttl;
@@ -1223,9 +1502,9 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port;
vni = rdst->remote_vni;
- dst = rdst->remote_ip;
+ dst = &rdst->remote_ip;
- if (!dst) {
+ if (vxlan_addr_any(dst)) {
if (did_rsc) {
/* short-circuited back to local bridge */
vxlan_encap_bypass(skb, vxlan, vxlan);
@@ -1237,7 +1516,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
old_iph = ip_hdr(skb);
ttl = vxlan->ttl;
- if (!ttl && IN_MULTICAST(ntohl(dst)))
+ if (!ttl && vxlan_addr_multicast(dst))
ttl = 1;
tos = vxlan->tos;
@@ -1246,48 +1525,101 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
src_port = vxlan_src_port(vxlan->port_min, vxlan->port_max, skb);
- memset(&fl4, 0, sizeof(fl4));
- fl4.flowi4_oif = rdst->remote_ifindex;
- fl4.flowi4_tos = RT_TOS(tos);
- fl4.daddr = dst;
- fl4.saddr = vxlan->saddr;
-
- rt = ip_route_output_key(dev_net(dev), &fl4);
- if (IS_ERR(rt)) {
- netdev_dbg(dev, "no route to %pI4\n", &dst);
- dev->stats.tx_carrier_errors++;
- goto tx_error;
- }
+ if (dst->sa.sa_family == AF_INET) {
+ memset(&fl4, 0, sizeof(fl4));
+ fl4.flowi4_oif = rdst->remote_ifindex;
+ fl4.flowi4_tos = RT_TOS(tos);
+ fl4.daddr = dst->sin.sin_addr.s_addr;
+ fl4.saddr = vxlan->saddr.sin.sin_addr.s_addr;
+
+ rt = ip_route_output_key(dev_net(dev), &fl4);
+ if (IS_ERR(rt)) {
+ netdev_dbg(dev, "no route to %pI4\n",
+ &dst->sin.sin_addr.s_addr);
+ dev->stats.tx_carrier_errors++;
+ goto tx_error;
+ }
- if (rt->dst.dev == dev) {
- netdev_dbg(dev, "circular route to %pI4\n", &dst);
- dev->stats.collisions++;
- goto rt_tx_error;
- }
+ if (rt->dst.dev == dev) {
+ netdev_dbg(dev, "circular route to %pI4\n",
+ &dst->sin.sin_addr.s_addr);
+ dev->stats.collisions++;
+ goto tx_error;
+ }
+
+ /* Bypass encapsulation if the destination is local */
+ if (rt->rt_flags & RTCF_LOCAL &&
+ !(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
+ struct vxlan_dev *dst_vxlan;
+
+ ip_rt_put(rt);
+ dst_vxlan = vxlan_find_vni(dev_net(dev), vni, dst_port);
+ if (!dst_vxlan)
+ goto tx_error;
+ vxlan_encap_bypass(skb, vxlan, dst_vxlan);
+ return;
+ }
- /* Bypass encapsulation if the destination is local */
- if (rt->rt_flags & RTCF_LOCAL &&
- !(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
- struct vxlan_dev *dst_vxlan;
+ tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
+ ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
- ip_rt_put(rt);
- dst_vxlan = vxlan_find_vni(dev_net(dev), vni, dst_port);
- if (!dst_vxlan)
+ err = vxlan_xmit_skb(dev_net(dev), vxlan->vn_sock, rt, skb,
+ fl4.saddr, dst->sin.sin_addr.s_addr,
+ tos, ttl, df, src_port, dst_port,
+ htonl(vni << 8));
+
+ if (err < 0)
+ goto rt_tx_error;
+ iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ struct sock *sk = vxlan->vn_sock->sock->sk;
+ struct dst_entry *ndst;
+ struct flowi6 fl6;
+ u32 flags;
+
+ memset(&fl6, 0, sizeof(fl6));
+ fl6.flowi6_oif = rdst->remote_ifindex;
+ fl6.daddr = dst->sin6.sin6_addr;
+ fl6.saddr = vxlan->saddr.sin6.sin6_addr;
+ fl6.flowi6_proto = skb->protocol;
+
+ if (ipv6_stub->ipv6_dst_lookup(sk, &ndst, &fl6)) {
+ netdev_dbg(dev, "no route to %pI6\n",
+ &dst->sin6.sin6_addr);
+ dev->stats.tx_carrier_errors++;
goto tx_error;
- vxlan_encap_bypass(skb, vxlan, dst_vxlan);
- return;
- }
+ }
- tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
- ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
+ if (ndst->dev == dev) {
+ netdev_dbg(dev, "circular route to %pI6\n",
+ &dst->sin6.sin6_addr);
+ dst_release(ndst);
+ dev->stats.collisions++;
+ goto tx_error;
+ }
- err = vxlan_xmit_skb(dev_net(dev), vxlan->vn_sock, rt, skb,
- fl4.saddr, dst, tos, ttl, df,
- src_port, dst_port, htonl(vni << 8));
+ /* Bypass encapsulation if the destination is local */
+ flags = ((struct rt6_info *)ndst)->rt6i_flags;
+ if (flags & RTF_LOCAL &&
+ !(flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
+ struct vxlan_dev *dst_vxlan;
+
+ dst_release(ndst);
+ dst_vxlan = vxlan_find_vni(dev_net(dev), vni, dst_port);
+ if (!dst_vxlan)
+ goto tx_error;
+ vxlan_encap_bypass(skb, vxlan, dst_vxlan);
+ return;
+ }
- if (err < 0)
- goto rt_tx_error;
- iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
+ ttl = ttl ? : ip6_dst_hoplimit(ndst);
+
+ err = vxlan6_xmit_skb(dev_net(dev), vxlan->vn_sock, ndst, skb,
+ dev, &fl6.saddr, &fl6.daddr, 0, ttl,
+ src_port, dst_port, htonl(vni << 8));
+#endif
+ }
return;
@@ -1464,8 +1796,8 @@ static int vxlan_open(struct net_device *dev)
if (!vs)
return -ENOTCONN;
- if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
- vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
+ if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip) &&
+ vxlan_group_used(vn, &vxlan->default_dst.remote_ip)) {
vxlan_sock_hold(vs);
dev_hold(dev);
queue_work(vxlan_wq, &vxlan->igmp_join);
@@ -1503,8 +1835,8 @@ static int vxlan_stop(struct net_device *dev)
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_sock *vs = vxlan->vn_sock;
- if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
- ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
+ if (vs && vxlan_addr_multicast(&vxlan->default_dst.remote_ip) &&
+ ! vxlan_group_used(vn, &vxlan->default_dst.remote_ip)) {
vxlan_sock_hold(vs);
dev_hold(dev);
queue_work(vxlan_wq, &vxlan->igmp_leave);
@@ -1552,7 +1884,10 @@ static void vxlan_setup(struct net_device *dev)
eth_hw_addr_random(dev);
ether_setup(dev);
- dev->hard_header_len = ETH_HLEN + VXLAN_HEADROOM;
+ if (vxlan->default_dst.remote_ip.sa.sa_family == AF_INET6)
+ dev->hard_header_len = ETH_HLEN + VXLAN6_HEADROOM;
+ else
+ dev->hard_header_len = ETH_HLEN + VXLAN_HEADROOM;
dev->netdev_ops = &vxlan_netdev_ops;
dev->destructor = free_netdev;
@@ -1597,8 +1932,10 @@ static void vxlan_setup(struct net_device *dev)
static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
[IFLA_VXLAN_ID] = { .type = NLA_U32 },
[IFLA_VXLAN_GROUP] = { .len = FIELD_SIZEOF(struct iphdr, daddr) },
+ [IFLA_VXLAN_GROUP6] = { .len = sizeof(struct in6_addr) },
[IFLA_VXLAN_LINK] = { .type = NLA_U32 },
[IFLA_VXLAN_LOCAL] = { .len = FIELD_SIZEOF(struct iphdr, saddr) },
+ [IFLA_VXLAN_LOCAL6] = { .len = sizeof(struct in6_addr) },
[IFLA_VXLAN_TOS] = { .type = NLA_U8 },
[IFLA_VXLAN_TTL] = { .type = NLA_U8 },
[IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
@@ -1669,58 +2006,132 @@ static void vxlan_del_work(struct work_struct *work)
kfree_rcu(vs, rcu);
}
-static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
- vxlan_rcv_t *rcv, void *data)
+#if IS_ENABLED(CONFIG_IPV6)
+/* Create UDP socket for encapsulation receive. AF_INET6 socket
+ * could be used for both IPv4 and IPv6 communications, but
+ * users may set bindv6only=1.
+ */
+static int create_v6_sock(struct net *net, __be16 port, struct socket **psock)
+{
+ struct sock *sk;
+ struct socket *sock;
+ struct sockaddr_in6 vxlan_addr = {
+ .sin6_family = AF_INET6,
+ .sin6_port = port,
+ };
+ int rc, val = 1;
+
+ rc = sock_create_kern(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock);
+ if (rc < 0) {
+ pr_debug("UDPv6 socket create failed\n");
+ return rc;
+ }
+
+ /* Put in proper namespace */
+ sk = sock->sk;
+ sk_change_net(sk, net);
+
+ kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
+ (char *)&val, sizeof(val));
+ rc = kernel_bind(sock, (struct sockaddr *)&vxlan_addr,
+ sizeof(struct sockaddr_in6));
+ if (rc < 0) {
+ pr_debug("bind for UDPv6 socket %pI6:%u (%d)\n",
+ &vxlan_addr.sin6_addr, ntohs(vxlan_addr.sin6_port), rc);
+ sk_release_kernel(sk);
+ return rc;
+ }
+ /* At this point, IPv6 module should have been loaded in
+ * sock_create_kern().
+ */
+ BUG_ON(!ipv6_stub);
+
+ *psock = sock;
+ /* Disable multicast loopback */
+ inet_sk(sk)->mc_loop = 0;
+ return 0;
+}
+
+#else
+
+static int create_v6_sock(struct net *net, __be16 port, struct socket **psock)
+{
+ return -EPFNOSUPPORT;
+}
+#endif
+
+static int create_v4_sock(struct net *net, __be16 port, struct socket **psock)
{
- struct vxlan_net *vn = net_generic(net, vxlan_net_id);
- struct vxlan_sock *vs;
struct sock *sk;
+ struct socket *sock;
struct sockaddr_in vxlan_addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = port,
};
int rc;
- unsigned int h;
-
- vs = kmalloc(sizeof(*vs), GFP_KERNEL);
- if (!vs) {
- pr_debug("memory alocation failure\n");
- return ERR_PTR(-ENOMEM);
- }
-
- for (h = 0; h < VNI_HASH_SIZE; ++h)
- INIT_HLIST_HEAD(&vs->vni_list[h]);
-
- INIT_WORK(&vs->del_work, vxlan_del_work);
/* Create UDP socket for encapsulation receive. */
- rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vs->sock);
+ rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
if (rc < 0) {
pr_debug("UDP socket create failed\n");
- kfree(vs);
- return ERR_PTR(rc);
+ return rc;
}
/* Put in proper namespace */
- sk = vs->sock->sk;
+ sk = sock->sk;
sk_change_net(sk, net);
- rc = kernel_bind(vs->sock, (struct sockaddr *) &vxlan_addr,
+ rc = kernel_bind(sock, (struct sockaddr *) &vxlan_addr,
sizeof(vxlan_addr));
if (rc < 0) {
pr_debug("bind for UDP socket %pI4:%u (%d)\n",
&vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
sk_release_kernel(sk);
+ return rc;
+ }
+
+ *psock = sock;
+ /* Disable multicast loopback */
+ inet_sk(sk)->mc_loop = 0;
+ return 0;
+}
+
+/* Create new listen socket if needed */
+static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
+ vxlan_rcv_t *rcv, void *data, bool ipv6)
+{
+ struct vxlan_net *vn = net_generic(net, vxlan_net_id);
+ struct vxlan_sock *vs;
+ struct socket *sock;
+ struct sock *sk;
+ int rc = 0;
+ unsigned int h;
+
+ vs = kmalloc(sizeof(*vs), GFP_KERNEL);
+ if (!vs)
+ return ERR_PTR(-ENOMEM);
+
+ for (h = 0; h < VNI_HASH_SIZE; ++h)
+ INIT_HLIST_HEAD(&vs->vni_list[h]);
+
+ INIT_WORK(&vs->del_work, vxlan_del_work);
+
+ if (ipv6)
+ rc = create_v6_sock(net, port, &sock);
+ else
+ rc = create_v4_sock(net, port, &sock);
+ if (rc < 0) {
kfree(vs);
return ERR_PTR(rc);
}
+
+ vs->sock = sock;
+ sk = sock->sk;
atomic_set(&vs->refcnt, 1);
vs->rcv = rcv;
vs->data = data;
- /* Disable multicast loopback */
- inet_sk(sk)->mc_loop = 0;
spin_lock(&vn->sock_lock);
hlist_add_head_rcu(&vs->hlist, vs_head(net, port));
spin_unlock(&vn->sock_lock);
@@ -1728,18 +2139,24 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
/* Mark socket as an encapsulation socket. */
udp_sk(sk)->encap_type = 1;
udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv;
- udp_encap_enable();
+#if IS_ENABLED(CONFIG_IPV6)
+ if (ipv6)
+ ipv6_stub->udpv6_encap_enable();
+ else
+#endif
+ udp_encap_enable();
+
return vs;
}
struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
vxlan_rcv_t *rcv, void *data,
- bool no_share)
+ bool no_share, bool ipv6)
{
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
struct vxlan_sock *vs;
- vs = vxlan_socket_create(net, port, rcv, data);
+ vs = vxlan_socket_create(net, port, rcv, data, ipv6);
if (!IS_ERR(vs))
return vs;
@@ -1772,7 +2189,7 @@ static void vxlan_sock_work(struct work_struct *work)
__be16 port = vxlan->dst_port;
struct vxlan_sock *nvs;
- nvs = vxlan_sock_add(net, port, vxlan_rcv, NULL, false);
+ nvs = vxlan_sock_add(net, port, vxlan_rcv, NULL, false, vxlan->flags & VXLAN_F_IPV6);
spin_lock(&vn->sock_lock);
if (!IS_ERR(nvs))
vxlan_vs_add_dev(nvs, vxlan);
@@ -1789,6 +2206,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
struct vxlan_rdst *dst = &vxlan->default_dst;
__u32 vni;
int err;
+ bool use_ipv6 = false;
if (!data[IFLA_VXLAN_ID])
return -EINVAL;
@@ -1796,11 +2214,32 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
vni = nla_get_u32(data[IFLA_VXLAN_ID]);
dst->remote_vni = vni;
- if (data[IFLA_VXLAN_GROUP])
- dst->remote_ip = nla_get_be32(data[IFLA_VXLAN_GROUP]);
+ if (data[IFLA_VXLAN_GROUP]) {
+ dst->remote_ip.sin.sin_addr.s_addr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
+ dst->remote_ip.sa.sa_family = AF_INET;
+ } else if (data[IFLA_VXLAN_GROUP6]) {
+ if (!IS_ENABLED(CONFIG_IPV6))
+ return -EPFNOSUPPORT;
+
+ nla_memcpy(&dst->remote_ip.sin6.sin6_addr, data[IFLA_VXLAN_GROUP6],
+ sizeof(struct in6_addr));
+ dst->remote_ip.sa.sa_family = AF_INET6;
+ use_ipv6 = true;
+ }
- if (data[IFLA_VXLAN_LOCAL])
- vxlan->saddr = nla_get_be32(data[IFLA_VXLAN_LOCAL]);
+ if (data[IFLA_VXLAN_LOCAL]) {
+ vxlan->saddr.sin.sin_addr.s_addr = nla_get_be32(data[IFLA_VXLAN_LOCAL]);
+ vxlan->saddr.sa.sa_family = AF_INET;
+ } else if (data[IFLA_VXLAN_LOCAL6]) {
+ if (!IS_ENABLED(CONFIG_IPV6))
+ return -EPFNOSUPPORT;
+
+ /* TODO: respect scope id */
+ nla_memcpy(&vxlan->saddr.sin6.sin6_addr, data[IFLA_VXLAN_LOCAL6],
+ sizeof(struct in6_addr));
+ vxlan->saddr.sa.sa_family = AF_INET6;
+ use_ipv6 = true;
+ }
if (data[IFLA_VXLAN_LINK] &&
(dst->remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]))) {
@@ -1812,12 +2251,23 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
return -ENODEV;
}
+#if IS_ENABLED(CONFIG_IPV6)
+ if (use_ipv6) {
+ struct inet6_dev *idev = __in6_dev_get(lowerdev);
+ if (idev && idev->cnf.disable_ipv6) {
+ pr_info("IPv6 is disabled via sysctl\n");
+ return -EPERM;
+ }
+ vxlan->flags |= VXLAN_F_IPV6;
+ }
+#endif
+
if (!tb[IFLA_MTU])
- dev->mtu = lowerdev->mtu - VXLAN_HEADROOM;
+ dev->mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
/* update header length based on lower device */
dev->hard_header_len = lowerdev->hard_header_len +
- VXLAN_HEADROOM;
+ (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM);
}
if (data[IFLA_VXLAN_TOS])
@@ -1868,7 +2318,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
/* create an fdb entry for default destination */
err = vxlan_fdb_create(vxlan, all_zeros_mac,
- vxlan->default_dst.remote_ip,
+ &vxlan->default_dst.remote_ip,
NUD_REACHABLE|NUD_PERMANENT,
NLM_F_EXCL|NLM_F_CREATE,
vxlan->dst_port, vxlan->default_dst.remote_vni,
@@ -1905,9 +2355,9 @@ static size_t vxlan_get_size(const struct net_device *dev)
{
return nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_ID */
- nla_total_size(sizeof(__be32)) +/* IFLA_VXLAN_GROUP */
+ nla_total_size(sizeof(struct in6_addr)) + /* IFLA_VXLAN_GROUP{6} */
nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LINK */
- nla_total_size(sizeof(__be32))+ /* IFLA_VXLAN_LOCAL */
+ nla_total_size(sizeof(struct in6_addr)) + /* IFLA_VXLAN_LOCAL{6} */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TTL */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TOS */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LEARNING */
@@ -1934,14 +2384,36 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
if (nla_put_u32(skb, IFLA_VXLAN_ID, dst->remote_vni))
goto nla_put_failure;
- if (dst->remote_ip && nla_put_be32(skb, IFLA_VXLAN_GROUP, dst->remote_ip))
- goto nla_put_failure;
+ if (!vxlan_addr_any(&dst->remote_ip)) {
+ if (dst->remote_ip.sa.sa_family == AF_INET) {
+ if (nla_put_be32(skb, IFLA_VXLAN_GROUP,
+ dst->remote_ip.sin.sin_addr.s_addr))
+ goto nla_put_failure;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ if (nla_put(skb, IFLA_VXLAN_GROUP6, sizeof(struct in6_addr),
+ &dst->remote_ip.sin6.sin6_addr))
+ goto nla_put_failure;
+#endif
+ }
+ }
if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex))
goto nla_put_failure;
- if (vxlan->saddr && nla_put_be32(skb, IFLA_VXLAN_LOCAL, vxlan->saddr))
- goto nla_put_failure;
+ if (!vxlan_addr_any(&vxlan->saddr)) {
+ if (vxlan->saddr.sa.sa_family == AF_INET) {
+ if (nla_put_be32(skb, IFLA_VXLAN_LOCAL,
+ vxlan->saddr.sin.sin_addr.s_addr))
+ goto nla_put_failure;
+#if IS_ENABLED(CONFIG_IPV6)
+ } else {
+ if (nla_put(skb, IFLA_VXLAN_LOCAL6, sizeof(struct in6_addr),
+ &vxlan->saddr.sin6.sin6_addr))
+ goto nla_put_failure;
+#endif
+ }
+ }
if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->ttl) ||
nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->tos) ||
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index ad342e3..d2b88ca 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -25,7 +25,7 @@ struct vxlan_sock {
struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
vxlan_rcv_t *rcv, void *data,
- bool no_share);
+ bool no_share, bool ipv6);
void vxlan_sock_release(struct vxlan_sock *vs);
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 04c0e7a..80394e8 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -314,6 +314,8 @@ enum {
IFLA_VXLAN_L2MISS,
IFLA_VXLAN_L3MISS,
IFLA_VXLAN_PORT, /* destination port */
+ IFLA_VXLAN_GROUP6,
+ IFLA_VXLAN_LOCAL6,
__IFLA_VXLAN_MAX
};
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c
index 36848bd..a006024 100644
--- a/net/openvswitch/vport-vxlan.c
+++ b/net/openvswitch/vport-vxlan.c
@@ -123,7 +123,7 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
vxlan_port = vxlan_vport(vport);
strncpy(vxlan_port->name, parms->name, IFNAMSIZ);
- vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true);
+ vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, false);
if (IS_ERR(vs)) {
ovs_vport_free(vport);
return (void *)vs;
--
1.7.7.6
^ permalink raw reply related
* [PATCH net-next v12 11/11] net: unify skb_udp_tunnel_segment() and skb_udp6_tunnel_segment()
From: Cong Wang @ 2013-08-31 5:44 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, Pravin Shelar, Cong Wang
In-Reply-To: <1377927878-23975-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
As suggested by Pravin, we can unify the code in case of duplicated
code.
Cc: Pravin Shelar <pshelar@nicira.com>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
net/ipv4/udp.c | 13 ++++++++++-
net/ipv6/udp_offload.c | 56 +-----------------------------------------------
2 files changed, 13 insertions(+), 56 deletions(-)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 0b24508..74d2c95 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2337,7 +2337,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
uh->len = htons(skb->len - udp_offset);
/* csum segment if tunnel sets skb with csum. */
- if (unlikely(uh->check)) {
+ if (protocol == htons(ETH_P_IP) && unlikely(uh->check)) {
struct iphdr *iph = ip_hdr(skb);
uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
@@ -2348,7 +2348,18 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
if (uh->check == 0)
uh->check = CSUM_MANGLED_0;
+ } else if (protocol == htons(ETH_P_IPV6)) {
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ u32 len = skb->len - udp_offset;
+
+ uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
+ len, IPPROTO_UDP, 0);
+ uh->check = csum_fold(skb_checksum(skb, udp_offset, len, 0));
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+ skb->ip_summed = CHECKSUM_NONE;
}
+
skb->protocol = protocol;
} while ((skb = skb->next));
out:
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 7e5e5ac..6055951 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -38,60 +38,6 @@ static int udp6_ufo_send_check(struct sk_buff *skb)
return 0;
}
-static struct sk_buff *skb_udp6_tunnel_segment(struct sk_buff *skb,
- netdev_features_t features)
-{
- struct sk_buff *segs = ERR_PTR(-EINVAL);
- int mac_len = skb->mac_len;
- int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
- int outer_hlen;
- netdev_features_t enc_features;
-
- if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
- goto out;
-
- skb->encapsulation = 0;
- __skb_pull(skb, tnl_hlen);
- skb_reset_mac_header(skb);
- skb_set_network_header(skb, skb_inner_network_offset(skb));
- skb->mac_len = skb_inner_network_offset(skb);
-
- /* segment inner packet. */
- enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
- segs = skb_mac_gso_segment(skb, enc_features);
- if (!segs || IS_ERR(segs))
- goto out;
-
- outer_hlen = skb_tnl_header_len(skb);
- skb = segs;
- do {
- struct udphdr *uh;
- struct ipv6hdr *ipv6h;
- int udp_offset = outer_hlen - tnl_hlen;
- u32 len;
-
- skb->mac_len = mac_len;
-
- skb_push(skb, outer_hlen);
- skb_reset_mac_header(skb);
- skb_set_network_header(skb, mac_len);
- skb_set_transport_header(skb, udp_offset);
- uh = udp_hdr(skb);
- uh->len = htons(skb->len - udp_offset);
- ipv6h = ipv6_hdr(skb);
- len = skb->len - udp_offset;
-
- uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
- len, IPPROTO_UDP, 0);
- uh->check = csum_fold(skb_checksum(skb, udp_offset, len, 0));
- if (uh->check == 0)
- uh->check = CSUM_MANGLED_0;
- skb->ip_summed = CHECKSUM_NONE;
- } while ((skb = skb->next));
-out:
- return segs;
-}
-
static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
netdev_features_t features)
{
@@ -129,7 +75,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
}
if (skb->encapsulation && skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL)
- segs = skb_udp6_tunnel_segment(skb, features);
+ segs = skb_udp_tunnel_segment(skb, features);
else {
/* Do software UFO. Complete and fill in the UDP checksum as HW cannot
* do checksum of UDP packets sent as multiple IP fragments.
--
1.7.7.6
^ permalink raw reply related
* [PATCH net-next v12 10/11] ipv6: Add generic UDP Tunnel segmentation
From: Cong Wang @ 2013-08-31 5:44 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Jesse Gross, Pravin B Shelar, Stephen Hemminger,
Cong Wang
In-Reply-To: <1377927878-23975-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
Similar to commit 731362674580cb0c696cd1b1a03d8461a10cf90a
(tunneling: Add generic Tunnel segmentation)
This patch adds generic tunneling offloading support for
IPv6-UDP based tunnels.
This can be used by tunneling protocols like VXLAN.
Cc: Jesse Gross <jesse@nicira.com>
Cc: Pravin B Shelar <pshelar@nicira.com>
Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
net/ipv6/ip6_offload.c | 4 +-
net/ipv6/udp_offload.c | 159 ++++++++++++++++++++++++++++++++---------------
2 files changed, 111 insertions(+), 52 deletions(-)
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index a263b99..d82de72 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -91,6 +91,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
unsigned int unfrag_ip6hlen;
u8 *prevhdr;
int offset = 0;
+ bool tunnel;
if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_UDP |
@@ -106,6 +107,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
goto out;
+ tunnel = skb->encapsulation;
ipv6h = ipv6_hdr(skb);
__skb_pull(skb, sizeof(*ipv6h));
segs = ERR_PTR(-EPROTONOSUPPORT);
@@ -126,7 +128,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
ipv6h = ipv6_hdr(skb);
ipv6h->payload_len = htons(skb->len - skb->mac_len -
sizeof(*ipv6h));
- if (proto == IPPROTO_UDP) {
+ if (!tunnel && proto == IPPROTO_UDP) {
unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
fptr = (struct frag_hdr *)(skb_network_header(skb) +
unfrag_ip6hlen);
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 5d1b8d7..7e5e5ac 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -21,26 +21,79 @@ static int udp6_ufo_send_check(struct sk_buff *skb)
const struct ipv6hdr *ipv6h;
struct udphdr *uh;
- /* UDP Tunnel offload on ipv6 is not yet supported. */
- if (skb->encapsulation)
- return -EINVAL;
-
if (!pskb_may_pull(skb, sizeof(*uh)))
return -EINVAL;
- ipv6h = ipv6_hdr(skb);
- uh = udp_hdr(skb);
+ if (likely(!skb->encapsulation)) {
+ ipv6h = ipv6_hdr(skb);
+ uh = udp_hdr(skb);
+
+ uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
+ IPPROTO_UDP, 0);
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ }
- uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
- IPPROTO_UDP, 0);
- skb->csum_start = skb_transport_header(skb) - skb->head;
- skb->csum_offset = offsetof(struct udphdr, check);
- skb->ip_summed = CHECKSUM_PARTIAL;
return 0;
}
+static struct sk_buff *skb_udp6_tunnel_segment(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ int mac_len = skb->mac_len;
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ int outer_hlen;
+ netdev_features_t enc_features;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
+ skb->encapsulation = 0;
+ __skb_pull(skb, tnl_hlen);
+ skb_reset_mac_header(skb);
+ skb_set_network_header(skb, skb_inner_network_offset(skb));
+ skb->mac_len = skb_inner_network_offset(skb);
+
+ /* segment inner packet. */
+ enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
+ segs = skb_mac_gso_segment(skb, enc_features);
+ if (!segs || IS_ERR(segs))
+ goto out;
+
+ outer_hlen = skb_tnl_header_len(skb);
+ skb = segs;
+ do {
+ struct udphdr *uh;
+ struct ipv6hdr *ipv6h;
+ int udp_offset = outer_hlen - tnl_hlen;
+ u32 len;
+
+ skb->mac_len = mac_len;
+
+ skb_push(skb, outer_hlen);
+ skb_reset_mac_header(skb);
+ skb_set_network_header(skb, mac_len);
+ skb_set_transport_header(skb, udp_offset);
+ uh = udp_hdr(skb);
+ uh->len = htons(skb->len - udp_offset);
+ ipv6h = ipv6_hdr(skb);
+ len = skb->len - udp_offset;
+
+ uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
+ len, IPPROTO_UDP, 0);
+ uh->check = csum_fold(skb_checksum(skb, udp_offset, len, 0));
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+ skb->ip_summed = CHECKSUM_NONE;
+ } while ((skb = skb->next));
+out:
+ return segs;
+}
+
static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
- netdev_features_t features)
+ netdev_features_t features)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
unsigned int mss;
@@ -75,47 +128,51 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
goto out;
}
- /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
- * do checksum of UDP packets sent as multiple IP fragments.
- */
- offset = skb_checksum_start_offset(skb);
- csum = skb_checksum(skb, offset, skb->len - offset, 0);
- offset += skb->csum_offset;
- *(__sum16 *)(skb->data + offset) = csum_fold(csum);
- skb->ip_summed = CHECKSUM_NONE;
-
- /* Check if there is enough headroom to insert fragment header. */
- tnl_hlen = skb_tnl_header_len(skb);
- if (skb_headroom(skb) < (tnl_hlen + frag_hdr_sz)) {
- if (gso_pskb_expand_head(skb, tnl_hlen + frag_hdr_sz))
- goto out;
+ if (skb->encapsulation && skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL)
+ segs = skb_udp6_tunnel_segment(skb, features);
+ else {
+ /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
+ * do checksum of UDP packets sent as multiple IP fragments.
+ */
+ offset = skb_checksum_start_offset(skb);
+ csum = skb_checksum(skb, offset, skb->len - offset, 0);
+ offset += skb->csum_offset;
+ *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Check if there is enough headroom to insert fragment header. */
+ tnl_hlen = skb_tnl_header_len(skb);
+ if (skb_headroom(skb) < (tnl_hlen + frag_hdr_sz)) {
+ if (gso_pskb_expand_head(skb, tnl_hlen + frag_hdr_sz))
+ goto out;
+ }
+
+ /* Find the unfragmentable header and shift it left by frag_hdr_sz
+ * bytes to insert fragment header.
+ */
+ unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
+ nexthdr = *prevhdr;
+ *prevhdr = NEXTHDR_FRAGMENT;
+ unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) +
+ unfrag_ip6hlen + tnl_hlen;
+ packet_start = (u8 *) skb->head + SKB_GSO_CB(skb)->mac_offset;
+ memmove(packet_start-frag_hdr_sz, packet_start, unfrag_len);
+
+ SKB_GSO_CB(skb)->mac_offset -= frag_hdr_sz;
+ skb->mac_header -= frag_hdr_sz;
+ skb->network_header -= frag_hdr_sz;
+
+ fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
+ fptr->nexthdr = nexthdr;
+ fptr->reserved = 0;
+ ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
+
+ /* Fragment the skb. ipv6 header and the remaining fields of the
+ * fragment header are updated in ipv6_gso_segment()
+ */
+ segs = skb_segment(skb, features);
}
- /* Find the unfragmentable header and shift it left by frag_hdr_sz
- * bytes to insert fragment header.
- */
- unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
- nexthdr = *prevhdr;
- *prevhdr = NEXTHDR_FRAGMENT;
- unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) +
- unfrag_ip6hlen + tnl_hlen;
- packet_start = (u8 *) skb->head + SKB_GSO_CB(skb)->mac_offset;
- memmove(packet_start-frag_hdr_sz, packet_start, unfrag_len);
-
- SKB_GSO_CB(skb)->mac_offset -= frag_hdr_sz;
- skb->mac_header -= frag_hdr_sz;
- skb->network_header -= frag_hdr_sz;
-
- fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
- fptr->nexthdr = nexthdr;
- fptr->reserved = 0;
- ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
-
- /* Fragment the skb. ipv6 header and the remaining fields of the
- * fragment header are updated in ipv6_gso_segment()
- */
- segs = skb_segment(skb, features);
-
out:
return segs;
}
--
1.7.7.6
^ permalink raw reply related
* [PATCH net-next v12 09/11] vxlan: add ipv6 proxy support
From: Cong Wang @ 2013-08-31 5:44 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, David Stevens, Cong Wang
In-Reply-To: <1377927878-23975-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
This patch adds the IPv6 version of "arp_reduce", ndisc_send_na()
will be needed.
Cc: David S. Miller <davem@davemloft.net>
Cc: David Stevens <dlstevens@us.ibm.com>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
drivers/net/vxlan.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++-
include/net/addrconf.h | 4 ++
include/net/ndisc.h | 5 +++
net/ipv6/af_inet6.c | 2 +
net/ipv6/ndisc.c | 8 ++--
5 files changed, 95 insertions(+), 6 deletions(-)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index c833763..3ffb22d 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1196,6 +1196,70 @@ out:
return NETDEV_TX_OK;
}
+#if IS_ENABLED(CONFIG_IPV6)
+static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct neighbour *n;
+ union vxlan_addr ipa;
+ const struct ipv6hdr *iphdr;
+ const struct in6_addr *saddr, *daddr;
+ struct nd_msg *msg;
+ struct inet6_dev *in6_dev = NULL;
+
+ in6_dev = __in6_dev_get(dev);
+ if (!in6_dev)
+ goto out;
+
+ if (!pskb_may_pull(skb, skb->len))
+ goto out;
+
+ iphdr = ipv6_hdr(skb);
+ saddr = &iphdr->saddr;
+ daddr = &iphdr->daddr;
+
+ if (ipv6_addr_loopback(daddr) ||
+ ipv6_addr_is_multicast(daddr))
+ goto out;
+
+ msg = (struct nd_msg *)skb_transport_header(skb);
+ if (msg->icmph.icmp6_code != 0 ||
+ msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
+ goto out;
+
+ n = neigh_lookup(ipv6_stub->nd_tbl, daddr, dev);
+
+ if (n) {
+ struct vxlan_fdb *f;
+
+ if (!(n->nud_state & NUD_CONNECTED)) {
+ neigh_release(n);
+ goto out;
+ }
+
+ f = vxlan_find_mac(vxlan, n->ha);
+ if (f && vxlan_addr_any(&(first_remote_rcu(f)->remote_ip))) {
+ /* bridge-local neighbor */
+ neigh_release(n);
+ goto out;
+ }
+
+ ipv6_stub->ndisc_send_na(dev, n, saddr, &msg->target,
+ !!in6_dev->cnf.forwarding,
+ true, false, false);
+ neigh_release(n);
+ } else if (vxlan->flags & VXLAN_F_L3MISS) {
+ ipa.sin6.sin6_addr = *daddr;
+ ipa.sa.sa_family = AF_INET6;
+ vxlan_ip_miss(dev, &ipa);
+ }
+
+out:
+ consume_skb(skb);
+ return NETDEV_TX_OK;
+}
+#endif
+
static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
@@ -1677,8 +1741,22 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
skb_reset_mac_header(skb);
eth = eth_hdr(skb);
- if ((vxlan->flags & VXLAN_F_PROXY) && ntohs(eth->h_proto) == ETH_P_ARP)
- return arp_reduce(dev, skb);
+ if ((vxlan->flags & VXLAN_F_PROXY)) {
+ if (ntohs(eth->h_proto) == ETH_P_ARP)
+ return arp_reduce(dev, skb);
+#if IS_ENABLED(CONFIG_IPV6)
+ else if (ntohs(eth->h_proto) == ETH_P_IPV6 &&
+ skb->len >= sizeof(struct ipv6hdr) + sizeof(struct nd_msg) &&
+ ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) {
+ struct nd_msg *msg;
+
+ msg = (struct nd_msg *)skb_transport_header(skb);
+ if (msg->icmph.icmp6_code == 0 &&
+ msg->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION)
+ return neigh_reduce(dev, skb);
+ }
+#endif
+ }
f = vxlan_find_mac(vxlan, eth->h_dest);
did_rsc = false;
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index bcf9573..fb314de 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -153,6 +153,10 @@ struct ipv6_stub {
int (*ipv6_dst_lookup)(struct sock *sk, struct dst_entry **dst,
struct flowi6 *fl6);
void (*udpv6_encap_enable)(void);
+ void (*ndisc_send_na)(struct net_device *dev, struct neighbour *neigh,
+ const struct in6_addr *daddr,
+ const struct in6_addr *solicited_addr,
+ bool router, bool solicited, bool override, bool inc_opt);
struct neigh_table *nd_tbl;
};
extern const struct ipv6_stub *ipv6_stub __read_mostly;
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 6fea323..3c4211f 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -204,6 +204,11 @@ extern void ndisc_send_ns(struct net_device *dev,
extern void ndisc_send_rs(struct net_device *dev,
const struct in6_addr *saddr,
const struct in6_addr *daddr);
+extern void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
+ const struct in6_addr *daddr,
+ const struct in6_addr *solicited_addr,
+ bool router, bool solicited, bool override,
+ bool inc_opt);
extern void ndisc_send_redirect(struct sk_buff *skb,
const struct in6_addr *target);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 1996a7c..136fe55 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -56,6 +56,7 @@
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
+#include <net/ndisc.h>
#ifdef CONFIG_IPV6_TUNNEL
#include <net/ip6_tunnel.h>
#endif
@@ -815,6 +816,7 @@ static const struct ipv6_stub ipv6_stub_impl = {
.ipv6_sock_mc_drop = ipv6_sock_mc_drop,
.ipv6_dst_lookup = ip6_dst_lookup,
.udpv6_encap_enable = udpv6_encap_enable,
+ .ndisc_send_na = ndisc_send_na,
.nd_tbl = &nd_tbl,
};
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index bb6fd95..14bd2f9 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -461,10 +461,10 @@ static void ndisc_send_skb(struct sk_buff *skb,
rcu_read_unlock();
}
-static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
- const struct in6_addr *daddr,
- const struct in6_addr *solicited_addr,
- bool router, bool solicited, bool override, bool inc_opt)
+void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
+ const struct in6_addr *daddr,
+ const struct in6_addr *solicited_addr,
+ bool router, bool solicited, bool override, bool inc_opt)
{
struct sk_buff *skb;
struct in6_addr tmpaddr;
--
1.7.7.6
^ permalink raw reply related
* [PATCH net-next v12 08/11] ipv6: move in6_dev_finish_destroy() into core kernel
From: Cong Wang @ 2013-08-31 5:44 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, Cong Wang
In-Reply-To: <1377927878-23975-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
in6_dev_put() will be needed by vxlan module, so is
in6_dev_finish_destroy().
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
net/ipv6/addrconf.c | 30 ------------------------------
net/ipv6/addrconf_core.c | 31 +++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index baaaead..2a66eaa 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -304,36 +304,6 @@ err_ip:
return -ENOMEM;
}
-static void snmp6_free_dev(struct inet6_dev *idev)
-{
- kfree(idev->stats.icmpv6msgdev);
- kfree(idev->stats.icmpv6dev);
- snmp_mib_free((void __percpu **)idev->stats.ipv6);
-}
-
-/* Nobody refers to this device, we may destroy it. */
-
-void in6_dev_finish_destroy(struct inet6_dev *idev)
-{
- struct net_device *dev = idev->dev;
-
- WARN_ON(!list_empty(&idev->addr_list));
- WARN_ON(idev->mc_list != NULL);
- WARN_ON(timer_pending(&idev->rs_timer));
-
-#ifdef NET_REFCNT_DEBUG
- pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL");
-#endif
- dev_put(dev);
- if (!idev->dead) {
- pr_warn("Freeing alive inet6 device %p\n", idev);
- return;
- }
- snmp6_free_dev(idev);
- kfree_rcu(idev, rcu);
-}
-EXPORT_SYMBOL(in6_dev_finish_destroy);
-
static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
{
struct inet6_dev *ndev;
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
index a864033..4c11cbc 100644
--- a/net/ipv6/addrconf_core.c
+++ b/net/ipv6/addrconf_core.c
@@ -6,6 +6,7 @@
#include <linux/export.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
+#include <net/ip.h>
#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
@@ -117,3 +118,33 @@ const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL
EXPORT_SYMBOL(in6addr_interfacelocal_allrouters);
const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT;
EXPORT_SYMBOL(in6addr_sitelocal_allrouters);
+
+static void snmp6_free_dev(struct inet6_dev *idev)
+{
+ kfree(idev->stats.icmpv6msgdev);
+ kfree(idev->stats.icmpv6dev);
+ snmp_mib_free((void __percpu **)idev->stats.ipv6);
+}
+
+/* Nobody refers to this device, we may destroy it. */
+
+void in6_dev_finish_destroy(struct inet6_dev *idev)
+{
+ struct net_device *dev = idev->dev;
+
+ WARN_ON(!list_empty(&idev->addr_list));
+ WARN_ON(idev->mc_list != NULL);
+ WARN_ON(timer_pending(&idev->rs_timer));
+
+#ifdef NET_REFCNT_DEBUG
+ pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL");
+#endif
+ dev_put(dev);
+ if (!idev->dead) {
+ pr_warn("Freeing alive inet6 device %p\n", idev);
+ return;
+ }
+ snmp6_free_dev(idev);
+ kfree_rcu(idev, rcu);
+}
+EXPORT_SYMBOL(in6_dev_finish_destroy);
--
1.7.7.6
^ permalink raw reply related
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