Netdev List
 help / color / mirror / Atom feed
* [PATCH net v1] ipv6/ila: fix nlsize calculation for lwtunnel
From: Nicolas Dichtel @ 2016-05-03  7:58 UTC (permalink / raw)
  To: davem; +Cc: netdev, Nicolas Dichtel, Tom Herbert
In-Reply-To: <CALx6S36jkPqx5U+B9akRYZ+xiRhozk_AdOmKBEr4N9mhwTKQMw@mail.gmail.com>

The handler 'ila_fill_encap_info' adds one attribute: ILA_ATTR_LOCATOR.

Fixes: 65d7ab8de582 ("net: Identifier Locator Addressing module")
CC: Tom Herbert <tom@herbertland.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---

RFC -> v1:
  - rebase on last net tree

 net/ipv6/ila/ila_lwt.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c
index 2ae3c4fd8aab..41f18de5dcc2 100644
--- a/net/ipv6/ila/ila_lwt.c
+++ b/net/ipv6/ila/ila_lwt.c
@@ -120,8 +120,7 @@ nla_put_failure:
 
 static int ila_encap_nlsize(struct lwtunnel_state *lwtstate)
 {
-	/* No encapsulation overhead */
-	return 0;
+	return nla_total_size(sizeof(u64)); /* ILA_ATTR_LOCATOR */
 }
 
 static int ila_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
-- 
2.8.1

^ permalink raw reply related

* Re: [PATCH v1 net] net/mlx4: Avoid wrong virtual mappings
From: Or Gerlitz @ 2016-05-03  7:45 UTC (permalink / raw)
  To: Haggai Abramovsky, David S. Miller
  Cc: Linux Netdev List, Sinan Kaya, Timur Tabi, Eran Ben Elisha,
	Yishai Hadas, Tal Alon, Saeed Mahameed
In-Reply-To: <1461740820-15386-1-git-send-email-hagaya@mellanox.com>

On Wed, Apr 27, 2016 at 10:07 AM, Haggai Abramovsky <hagaya@mellanox.com> wrote:
> The dma_alloc_coherent() function returns a virtual address which can
> be used for coherent access to the underlying memory.  On some
> architectures, like arm64, undefined behavior results if this memory is
> also accessed via virtual mappings that are not coherent.  Because of
> their undefined nature, operations like virt_to_page() return garbage
> when passed virtual addresses obtained from dma_alloc_coherent().  Any
> subsequent mappings via vmap() of the garbage page values are unusable
> and result in bad things like bus errors (synchronous aborts in ARM64
> speak).
>
> The mlx4 driver contains code that does the equivalent of:
> vmap(virt_to_page(dma_alloc_coherent)), this results in an OOPs when the
> device is opened.
>
> Prevent Ethernet driver to run this problematic code by forcing it to
> allocate contiguous memory. As for the Infiniband driver, at first we
> are trying to allocate contiguous memory, but in case of failure roll
> back to work with fragmented memory.

Dave,

The patch changes the driver to do single allocation for potentially
very large HW WQE
descriptor buffers such as those used by the RDMA (mlx5_ib) driver.
The IB driver does
have the means to cope with fragmented allocations, and under RDMA use
cases, QPs
are being frequently set not only on system startup, but rather
throughout all the lifecycles
(e.g every now and then in production systems). As of all the above,
we prefer the patch
to go to net-next and not net. This will make the code (1) correct,
and (2) we have the chance
to do the whatever investigations needed and if required add a follow
up fix for 4.7-rc

Or.

> Signed-off-by: Haggai Abramovsky <hagaya@mellanox.com>
> Signed-off-by: Yishai Hadas <yishaih@mellanox.com>
> Reported-by: David Daney <david.daney@cavium.com>
> Tested-by: Sinan Kaya <okaya@codeaurora.org>

^ permalink raw reply

* [PATCH iproute2 v2] tc: add bash-completion function
From: Quentin Monnet @ 2016-05-03  7:39 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Alexei Starovoitov, Jamal Hadi Salim, Vincent Jardin, netdev
In-Reply-To: <20160502151414.0c9c3e3a@xeon-e3>

Add function for command completion for tc in bash, and update Makefile
to install it under /usr/share/bash-completion/completions/.

Inside iproute2 repository, the completion code is in a new
`bash-completion` toplevel directory.

v2: Remove `if` statement in Makefile: do not try to install in
    /etc/bash_completion.d/ if /usr/share/bash-completion/completions/
    is not found; instead, the user can override the installation path
    with the specific environment variable.

Signed-off-by: Quentin Monnet <quentin.monnet@6wind.com>
---
 Makefile           |   3 +
 bash-completion/tc | 723 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 726 insertions(+)
 create mode 100644 bash-completion/tc

diff --git a/Makefile b/Makefile
index 0190aa004a79..eb571a5accf8 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,7 @@ DOCDIR?=$(DATADIR)/doc/iproute2
 MANDIR?=$(DATADIR)/man
 ARPDDIR?=/var/lib/arpd
 KERNEL_INCLUDE?=/usr/include
+BASH_COMPDIR?=$(DATADIR)/bash-completion/completions
 
 # Path to db_185.h include
 DBM_INCLUDE:=$(DESTDIR)/usr/include
@@ -66,6 +67,8 @@ install: all
 		$(DESTDIR)$(DOCDIR)/examples/diffserv
 	@for i in $(SUBDIRS) doc; do $(MAKE) -C $$i install; done
 	install -m 0644 $(shell find etc/iproute2 -maxdepth 1 -type f) $(DESTDIR)$(CONFDIR)
+	install -m 0755 -d $(DESTDIR)$(BASH_COMPDIR)
+	install -m 0644 bash-completion/tc $(DESTDIR)$(BASH_COMPDIR)
 
 snapshot:
 	echo "static const char SNAPSHOT[] = \""`date +%y%m%d`"\";" \
diff --git a/bash-completion/tc b/bash-completion/tc
new file mode 100644
index 000000000000..79dd5fcc172c
--- /dev/null
+++ b/bash-completion/tc
@@ -0,0 +1,723 @@
+# tc(8) completion                                         -*- shell-script -*-
+# Copyright 2016 6WIND S.A.
+# Copyright 2016 Quentin Monnet <quentin.monnet@6wind.com>
+
+# Takes a list of words in argument; each one of them is added to COMPREPLY if
+# it is not already present on the command line. Returns no value.
+_tc_once_attr()
+{
+    local w subcword found
+    for w in $*; do
+        found=0
+        for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do
+            if [[ $w == ${words[subcword]} ]]; then
+                found=1
+                break
+            fi
+        done
+        [[ $found -eq 0 ]] && \
+            COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) )
+    done
+}
+
+# Takes a list of words in argument; adds them all to COMPREPLY if none of them
+# is already present on the command line. Returns no value.
+_tc_one_of_list()
+{
+    local w subcword
+    for w in $*; do
+        for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do
+            [[ $w == ${words[subcword]} ]] && return 1
+        done
+    done
+    COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
+}
+
+# Returns "$cur ${cur}arg1 ${cur}arg2 ..."
+_tc_expand_units()
+{
+    [[ $cur =~ ^[0-9]+ ]] || return 1
+    local value=${cur%%[^0-9]*}
+    [[ $cur == $value ]] && echo $cur
+    echo ${@/#/$value}
+}
+
+# Complete based on given word, usually $prev (or possibly the word before),
+# for when an argument or an option name has but a few possible arguments (so
+# tc does not take particular commands into account here).
+# Returns 0 is completion should stop after running this function, 1 otherwise.
+_tc_direct_complete()
+{
+    case $1 in
+        # Command options
+        dev)
+            _available_interfaces
+            return 0
+            ;;
+        classid)
+            return 0
+            ;;
+        estimator)
+            local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
+            COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
+            return 0
+            ;;
+        handle)
+            return 0
+            ;;
+        parent|flowid)
+            local i iface ids cmd
+            for (( i=3; i < ${#words[@]}-2; i++ )); do
+                [[ ${words[i]} == dev ]] && iface=${words[i+1]}
+                break
+            done
+            for cmd in qdisc class; do
+                if [[ -n $iface ]]; then
+                    ids+=$( tc $cmd show dev $iface 2>/dev/null | \
+                        cut -d\  -f 3 )" "
+                else
+                    ids+=$( tc $cmd show 2>/dev/null | cut -d\  -f 3 )
+                fi
+            done
+            [[ $ids != " " ]] && \
+                COMPREPLY+=( $( compgen -W "$ids" -- "$cur" ) )
+            return 0
+            ;;
+        protocol) # list comes from lib/ll_proto.c
+            COMPREPLY+=( $( compgen -W ' 802.1Q 802.1ad 802_2 802_3 LLDP aarp \
+                all aoe arp atalk atmfate atmmpoa ax25 bpq can control cust \
+                ddcmp dec diag dna_dl dna_rc dna_rt econet ieeepup ieeepupat \
+                ip ipv4 ipv6 ipx irda lat localtalk loop mobitex ppp_disc \
+                ppp_mp ppp_ses ppptalk pup pupat rarp sca snap tipc tr_802_2 \
+                wan_ppp x25' -- "$cur" ) )
+            return 0
+            ;;
+        prio)
+            return 0
+            ;;
+        stab)
+            COMPREPLY+=( $( compgen -W 'mtu tsize mpu overhead
+                linklayer' -- "$cur" ) )
+            ;;
+
+        # Qdiscs and classes options
+        alpha|bands|beta|buckets|corrupt|debug|decrement|default|\
+        default_index|depth|direct_qlen|divisor|duplicate|ewma|flow_limit|\
+        flows|hh_limit|increment|indices|linklayer|non_hh_weight|num_tc|\
+        penalty_burst|penalty_rate|prio|priomap|probability|queues|r2q|\
+        reorder|vq|vqs)
+            return 0
+            ;;
+        setup)
+            COMPREPLY+=( $( compgen -W 'vqs' -- "$cur" ) )
+            return 0
+            ;;
+        hw)
+            COMPREPLY+=( $( compgen -W '1 0' -- "$cur" ) )
+            return 0
+            ;;
+        distribution)
+            COMPREPLY+=( $( compgen -W 'uniform normal pareto
+                paretonormal' -- "$cur" ) )
+            return 0
+            ;;
+        loss)
+            COMPREPLY+=( $( compgen -W 'random state gmodel' -- "$cur" ) )
+            return 0
+            ;;
+
+        # Qdiscs and classes options options
+        gap|gmodel|state)
+            return 0
+            ;;
+
+        # Filters options
+        map)
+            COMPREPLY+=( $( compgen -W 'key' -- "$cur" ) )
+            return 0
+            ;;
+        hash)
+            COMPREPLY+=( $( compgen -W 'keys' -- "$cur" ) )
+            return 0
+            ;;
+        indev)
+            _available_interfaces
+            return 0
+            ;;
+        eth_type)
+            COMPREPLY+=( $( compgen -W 'ipv4 ipv6' -- "$cur" ) )
+            return 0
+            ;;
+        ip_proto)
+            COMPREPLY+=( $( compgen -W 'tcp udp' -- "$cur" ) )
+            return 0
+            ;;
+
+        # Filters options options
+        key|keys)
+            [[ ${words[@]} =~ graft ]] && return 1
+            COMPREPLY+=( $( compgen -W 'src dst proto proto-src proto-dst iif \
+                priority mark nfct nfct-src nfct-dst nfct-proto-src \
+                nfct-proto-dst rt-classid sk-uid sk-gid vlan-tag rxhash' -- \
+                "$cur" ) )
+            return 0
+            ;;
+
+        # BPF options - used for filters, actions, and exec
+        export|bytecode|bytecode-file|object-file)
+            _filedir
+            return 0
+            ;;
+        object-pinned|graft) # Pinned object is probably under /sys/fs/bpf/
+            [[ -n "$cur" ]] && _filedir && return 0
+            COMPREPLY=( $( compgen -G "/sys/fs/bpf/*" -- "$cur" ) ) || _filedir
+            compopt -o nospace
+            return 0
+            ;;
+        section)
+            if (type objdump > /dev/null 2>&1) ; then
+                local fword objfile section_list
+                for (( fword=3; fword < ${#words[@]}-3; fword++ )); do
+                    if [[ ${words[fword]} == object-file ]]; then
+                        objfile=${words[fword+1]}
+                        break
+                    fi
+                done
+                section_list=$( objdump -h $objfile 2>/dev/null | \
+                    sed -n 's/^ *[0-9]\+ \([^ ]*\) *.*/\1/p' )
+                COMPREPLY+=( $( compgen -W "$section_list" -- "$cur" ) )
+            fi
+            return 0
+            ;;
+        import|run)
+            _filedir
+            return 0
+            ;;
+        type)
+            COMPREPLY+=( $( compgen -W 'cls act' -- "$cur" ) )
+            return 0
+            ;;
+
+        # Actions options
+        random)
+            _tc_one_of_list 'netrand determ'
+            return 0
+            ;;
+
+        # Units for option arguments
+        bandwidth|maxrate|peakrate|rate)
+            local list=$( _tc_expand_units 'bit' \
+                'kbit' 'kibit' 'kbps' 'kibps' \
+                'mbit' 'mibit' 'mbps' 'mibps' \
+                'gbit' 'gibit' 'gbps' 'gibps' \
+                'tbit' 'tibit' 'tbps' 'tibps' )
+            COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
+            ;;
+        admit_bytes|avpkt|burst|cell|initial_quantum|limit|max|min|mtu|mpu|\
+        overhead|quantum|redflowlist)
+            local list=$( _tc_expand_units \
+                'b' 'kbit' 'k' 'mbit' 'm' 'gbit' 'g' )
+            COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
+            ;;
+        db|delay|evict_timeout|interval|latency|perturb|rehash|reset_timeout|\
+        target|tupdate)
+            local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
+            COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) )
+            ;;
+    esac
+    return 1
+}
+
+# Complete with options names for qdiscs. Each qdisc has its own set of options
+# and it seems we cannot really parse it from anywhere, so we add it manually
+# in this function.
+# Returns 0 is completion should stop after running this function, 1 otherwise.
+_tc_qdisc_options()
+{
+    case $1 in
+        choke)
+            _tc_once_attr 'limit bandwidth ecn min max burst'
+            return 0
+            ;;
+        codel)
+            _tc_once_attr 'limit target interval'
+            _tc_one_of_list 'ecn noecn'
+            return 0
+            ;;
+        bfifo|pfifo|pfifo_head_drop)
+            _tc_once_attr 'limit'
+            return 0
+            ;;
+        fq)
+            _tc_once_attr 'limit flow_limit quantum initial_quantum maxrate \
+                buckets'
+            _tc_one_of_list 'pacing nopacing'
+            return 0
+            ;;
+        fq_codel)
+            _tc_once_attr 'limit flows target interval quantum'
+            _tc_one_of_list 'ecn noecn'
+            return 0
+            ;;
+        gred)
+            _tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \
+                burst probability bandwidth'
+            return 0
+            ;;
+        hhf)
+            _tc_once_attr 'limit quantum hh_limit reset_timeout admit_bytes \
+                evict_timeout non_hh_weight'
+            return 0
+            ;;
+        mqprio)
+            _tc_once_attr 'num_tc map queues hw'
+            return 0
+            ;;
+        netem)
+            _tc_once_attr 'delay distribution corrupt duplicate loss ecn \
+                reorder rate'
+            return 0
+            ;;
+        pie)
+            _tc_once_attr 'limit target tupdate alpha beta'
+            _tc_one_of_list 'bytemode nobytemode'
+            _tc_one_of_list 'ecn noecn'
+            return 0
+            ;;
+        red)
+            _tc_once_attr 'limit min max avpkt burst adaptive probability \
+                bandwidth ecn harddrop'
+            return 0
+            ;;
+        rr|prio)
+            _tc_once_attr 'bands priomap multiqueue'
+            return 0
+            ;;
+        sfb)
+            _tc_once_attr 'rehash db limit max target increment decrement \
+                penalty_rate penalty_burst'
+            return 0
+            ;;
+        sfq)
+            _tc_once_attr 'limit perturb quantum divisor flows depth headdrop \
+                redflowlimit min max avpkt burst probability ecn harddrop'
+            return 0
+            ;;
+        tbf)
+            _tc_once_attr 'limit burst rate mtu peakrate latency overhead \
+                linklayer'
+            return 0
+            ;;
+        cbq)
+            _tc_once_attr 'bandwidth avpkt mpu cell ewma'
+            return 0
+            ;;
+        dsmark)
+            _tc_once_attr 'indices default_index set_tc_index'
+            return 0
+            ;;
+        hfsc)
+            _tc_once_attr 'default'
+            return 0
+            ;;
+        htb)
+            _tc_once_attr 'default r2q direct_qlen debug'
+            return 0
+            ;;
+        multiq|pfifo_fast|atm|drr|qfq)
+            return 0
+            ;;
+    esac
+    return 1
+}
+
+# Complete with options names for BPF filters or actions.
+# Returns 0 is completion should stop after running this function, 1 otherwise.
+_tc_bpf_options()
+{
+    [[ ${words[${#words[@]}-3]} == object-file ]] && \
+        _tc_once_attr 'section export'
+    [[ ${words[${#words[@]}-5]} == object-file ]] && \
+        [[ ${words[${#words[@]}-3]} =~ (section|export) ]] && \
+        _tc_once_attr 'section export'
+    _tc_one_of_list 'bytecode bytecode-file object-file object-pinned'
+    _tc_once_attr 'verbose index direct-action action classid'
+    return 0
+}
+
+# Complete with options names for filters.
+# Returns 0 is completion should stop after running this function, 1 otherwise.
+_tc_filter_options()
+{
+    case $1 in
+        basic)
+            _tc_once_attr 'match action classid'
+            return 0
+            ;;
+        bpf)
+            _tc_bpf_options
+            return 0
+            ;;
+        cgroup)
+            _tc_once_attr 'match action'
+            return 0
+            ;;
+        flow)
+            local i
+            for (( i=5; i < ${#words[@]}-1; i++ )); do
+                if [[ ${words[i]} =~ ^keys?$ ]]; then
+                    _tc_direct_complete 'key'
+                    COMPREPLY+=( $( compgen -W 'or and xor rshift addend' -- \
+                        "$cur" ) )
+                    break
+                fi
+            done
+            _tc_once_attr 'map hash divisor baseclass match action'
+            return 0
+            ;;
+        flower)
+            _tc_once_attr 'action classid indev dst_mac src_mac eth_type \
+                ip_proto dst_ip src_ip dst_port src_port'
+            return 0
+            ;;
+        fw)
+            _tc_once_attr 'action classid'
+            return 0
+            ;;
+        route)
+            _tc_one_of_list 'from fromif'
+            _tc_once_attr 'to classid action'
+            return 0
+            ;;
+        rsvp)
+            _tc_once_attr 'ipproto session sender classid action tunnelid \
+                tunnel flowlabel spi/ah spi/esp u8 u16 u32'
+            [[ ${words[${#words[@]}-3]} == tunnel ]] && \
+                    COMPREPLY+=( $( compgen -W 'skip' -- "$cur" ) )
+            [[ ${words[${#words[@]}-3]} =~ u(8|16|32) ]] && \
+                    COMPREPLY+=( $( compgen -W 'mask' -- "$cur" ) )
+            [[ ${words[${#words[@]}-3]} == mask ]] && \
+                    COMPREPLY+=( $( compgen -W 'at' -- "$cur" ) )
+            return 0
+            ;;
+        tcindex)
+            _tc_once_attr 'hash mask shift classid action'
+            _tc_one_of_list 'pass_on fall_through'
+            return 0
+            ;;
+        u32)
+            _tc_once_attr 'match link classid action offset ht hashkey sample'
+            COMPREPLY+=( $( compgen -W 'ip ip6 udp tcp icmp u8 u16 u32 mark \
+                divisor' -- "$cur" ) )
+            return 0
+            ;;
+    esac
+    return 1
+}
+
+# Complete with options names for actions.
+# Returns 0 is completion should stop after running this function, 1 otherwise.
+_tc_action_options()
+{
+    case $1 in
+        bpf)
+            _tc_bpf_options
+            return 0
+            ;;
+        mirred)
+            _tc_one_of_list 'ingress egress'
+            _tc_one_of_list 'mirror redirect'
+            _tc_once_attr 'index dev'
+            return 0
+            ;;
+        gact)
+            _tc_one_of_list 'reclassify drop continue pass'
+            _tc_once_attr 'random'
+            return 0
+            ;;
+    esac
+    return 1
+}
+
+# Complete with options names for exec.
+# Returns 0 is completion should stop after running this function, 1 otherwise.
+_tc_exec_options()
+{
+    case $1 in
+        import)
+            [[ ${words[${#words[@]}-3]} == import ]] && \
+                _tc_once_attr 'run'
+            return 0
+            ;;
+        graft)
+            COMPREPLY+=( $( compgen -W 'key type' -- "$cur" ) )
+            [[ ${words[${#words[@]}-3]} == object-file ]] && \
+                _tc_once_attr 'type'
+            _tc_bpf_options
+            return 0
+            ;;
+    esac
+    return 1
+}
+
+# Main completion function
+# Logic is as follows:
+#   1. Check if previous word is a global option; if so, propose arguments.
+#   2. Check if current word is a global option; if so, propose completion.
+#   3. Check for the presence of a main command (qdisc|class|filter|...). If
+#      there is one, first call _tc_direct_complete to see if previous word is
+#      waiting for a particular completion. If so, propose completion and exit.
+#   4. Extract main command and -- if available -- its subcommand
+#      (add|delete|show|...).
+#   5. Propose completion based on main and sub- command in use. Additional
+#      functions may be called for qdiscs, classes or filter options.
+_tc()
+{
+    local cur prev words cword
+    _init_completion || return
+
+    case $prev in
+        -V|-Version)
+            return 0
+            ;;
+        -b|-batch|-cf|-conf)
+            _filedir
+            return 0
+            ;;
+        -force)
+            COMPREPLY=( $( compgen -W '-batch' -- "$cur" ) )
+            return 0
+            ;;
+        -nm|name)
+            [[ -r /etc/iproute2/tc_cls ]] || \
+                COMPREPLY=( $( compgen -W '-conf' -- "$cur" ) )
+            return 0
+            ;;
+        -n|-net|-netns)
+            local nslist=$( ip netns list 2>/dev/null )
+            COMPREPLY+=( $( compgen -W "$nslist" -- "$cur" ) )
+            return 0
+            ;;
+        -tshort)
+            _tc_once_attr '-statistics'
+            COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) )
+            return 0
+            ;;
+        -timestamp)
+            _tc_once_attr '-statistics -tshort'
+            COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) )
+            return 0
+            ;;
+    esac
+
+    # Search for main commands
+    local subcword cmd subcmd
+    for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do
+        [[ ${words[subcword]} == -b?(atch) ]] && return 0
+        [[ -n $cmd ]] && subcmd=${words[subcword]} && break
+        [[ ${words[subcword]} != -* && \
+            ${words[subcword-1]} != -@(n?(et?(ns))|c?(on)f) ]] && \
+            cmd=${words[subcword]}
+    done
+
+    if [[ -z $cmd ]]; then
+        case $cur in
+            -*)
+                local c='-Version -statistics -details -raw -pretty \
+                    -iec -graphe -batch -name -netns -timestamp'
+                [[ $cword -eq 1 ]] && c+=' -force'
+                COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
+                return 0
+                ;;
+            *)
+                COMPREPLY=( $( compgen -W "help $( tc help 2>&1 | \
+                    command sed \
+                    -e '/OBJECT := /!d' \
+                    -e 's/.*{//' \
+                    -e 's/}.*//' \
+                    -e \ 's/|//g' )" -- "$cur" ) )
+                return 0
+                ;;
+        esac
+    fi
+
+    [[ $subcmd == help ]] && return 0
+
+    # For this set of commands we may create COMPREPLY just by analysing the
+    # previous word, if it expects for a specific list of options or values.
+    if [[ $cmd =~ (qdisc|class|filter|action|exec) ]]; then
+        _tc_direct_complete $prev && return 0
+        if [[ ${words[${#words[@]}-3]} == estimator ]]; then
+            local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' )
+            COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) && return 0
+        fi
+    fi
+
+    # Completion depends on main command and subcommand in use.
+    case $cmd in
+        qdisc)
+            case $subcmd in
+                add|change|replace|link|del|delete)
+                    if [[ $(($cword-$subcword)) -eq 1 ]]; then
+                        COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
+                        return 0
+                    fi
+                    local qdisc qdwd QDISC_KIND=' choke codel bfifo pfifo \
+                        pfifo_head_drop fq fq_codel gred hhf mqprio multiq \
+                        netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \
+                        dsmark hfsc htb prio qfq '
+                    for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do
+                        if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then
+                            qdisc=${words[qdwd]}
+                            _tc_qdisc_options $qdisc && return 0
+                        fi
+                    done
+                    _tc_one_of_list $QDISC_KIND
+                    _tc_one_of_list 'root ingress parent clsact'
+                    _tc_once_attr 'handle estimator stab'
+                    ;;
+                show)
+                    _tc_once_attr 'dev'
+                    _tc_one_of_list 'ingress clsact'
+                    _tc_once_attr '-statistics -details -raw -pretty -iec \
+                        -graph -name'
+                    ;;
+                help)
+                    return 0
+                    ;;
+                *)
+                    [[ $cword -eq $subcword ]] && \
+                        COMPREPLY=( $( compgen -W 'help add delete change \
+                            replace link show' -- "$cur" ) )
+                    ;;
+            esac
+            ;;
+
+        class)
+            case $subcmd in
+                add|change|replace|del|delete)
+                    if [[ $(($cword-$subcword)) -eq 1 ]]; then
+                        COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
+                        return 0
+                    fi
+                    local qdisc qdwd QDISC_KIND=' choke codel bfifo pfifo \
+                        pfifo_head_drop fq fq_codel gred hhf mqprio multiq \
+                        netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \
+                        dsmark hfsc htb prio qfq '
+                    for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do
+                        if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then
+                            qdisc=${words[qdwd]}
+                            _tc_qdisc_options $qdisc && return 0
+                        fi
+                    done
+                    _tc_one_of_list $QDISC_KIND
+                    _tc_one_of_list 'root parent'
+                    _tc_once_attr 'classid'
+                    ;;
+                show)
+                    _tc_once_attr 'dev'
+                    _tc_one_of_list 'root parent'
+                    _tc_once_attr '-statistics -details -raw -pretty -iec \
+                        -graph -name'
+                    ;;
+                help)
+                    return 0
+                    ;;
+                *)
+                    [[ $cword -eq $subcword ]] && \
+                        COMPREPLY=( $( compgen -W 'help add delete change \
+                            replace show' -- "$cur" ) )
+                    ;;
+            esac
+            ;;
+
+        filter)
+            case $subcmd in
+                add|change|replace|del|delete)
+                    if [[ $(($cword-$subcword)) -eq 1 ]]; then
+                        COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
+                        return 0
+                    fi
+                    local filter fltwd FILTER_KIND=' basic bpf cgroup flow \
+                        flower fw route rsvp tcindex u32 '
+                    for ((fltwd=$subcword; fltwd < ${#words[@]}-1; fltwd++));
+                    do
+                        if [[ $FILTER_KIND =~ ' '${words[fltwd]}' ' ]]; then
+                            filter=${words[fltwd]}
+                            _tc_filter_options $filter && return 0
+                        fi
+                    done
+                    _tc_one_of_list $FILTER_KIND
+                    _tc_one_of_list 'root ingress egress parent'
+                    _tc_once_attr 'handle estimator pref protocol'
+                    ;;
+                show)
+                    _tc_once_attr 'dev'
+                    _tc_one_of_list 'root ingress egress parent'
+                    _tc_once_attr '-statistics -details -raw -pretty -iec \
+                        -graph -name'
+                    ;;
+                help)
+                    return 0
+                    ;;
+                *)
+                    [[ $cword -eq $subcword ]] && \
+                        COMPREPLY=( $( compgen -W 'help add delete change \
+                            replace show' -- "$cur" ) )
+                    ;;
+            esac
+            ;;
+
+        action)
+            case $subcmd in
+                add|change|replace)
+                    local action acwd ACTION_KIND=' gact mirred bpf '
+                    for ((acwd=$subcword; acwd < ${#words[@]}-1; acwd++)); do
+                        if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then
+                            action=${words[acwd]}
+                            _tc_action_options $action && return 0
+                        fi
+                    done
+                    _tc_one_of_list $ACTION_KIND
+                    ;;
+                get|del|delete)
+                    _tc_once_attr 'index'
+                    ;;
+                lst|list|flush|show)
+                    _tc_one_of_list $ACTION_KIND
+                    ;;
+                *)
+                    [[ $cword -eq $subcword ]] && \
+                        COMPREPLY=( $( compgen -W 'help add delete change \
+                            replace show list flush action' -- "$cur" ) )
+                    ;;
+            esac
+            ;;
+
+        monitor)
+            COMPREPLY=( $( compgen -W 'help' -- "$cur" ) )
+            ;;
+
+        exec)
+            case $subcmd in
+                bpf)
+                    local excmd exwd EXEC_KIND=' import debug graft '
+                    for ((exwd=$subcword; exwd < ${#words[@]}-1; exwd++)); do
+                        if [[ $EXEC_KIND =~ ' '${words[exwd]}' ' ]]; then
+                            excmd=${words[exwd]}
+                            _tc_exec_options $excmd && return 0
+                        fi
+                    done
+                    _tc_one_of_list $EXEC_KIND
+                    ;;
+                *)
+                    [[ $cword -eq $subcword ]] && \
+                        COMPREPLY=( $( compgen -W 'bpf' -- "$cur" ) )
+                    ;;
+            esac
+            ;;
+    esac
+} &&
+complete -F _tc tc
+
+# ex: ts=4 sw=4 et filetype=sh
-- 
2.1.4

^ permalink raw reply related

* [PATCH 1/2] nl80211: Allow privileged operations from user namespaces
From: Martin Willi @ 2016-05-03  6:53 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, netdev
In-Reply-To: <1462258398-6749-1-git-send-email-martin@strongswan.org>

While a wiphy can be transferred to network namespaces, a process having
CAP_NET_ADMIN in a non-initial user namespace can not administrate such
devices due to the genetlink GENL_ADMIN_PERM restrictions.

For openvswitch having the same issue, a new GENL_UNS_ADMIN_PERM flag has
been introduced, commit 4a92602aa1cd ("openvswitch: allow management from
inside user namespaces"). This patch changes all privileged operations
operating on a wiphy, dev or wdev to allow their administration using the
same mechanism. All operations use either NEED_WIPHY, NEED_WDEV or
NEED_NETDEV, which implies a namespace aware lookup of the device. The only
exception is NL80211_CMD_SET_WIPHY, which explicitly uses a namespace aware
lookup.

Signed-off-by: Martin Willi <martin@strongswan.org>
---
 net/wireless/nl80211.c | 150 ++++++++++++++++++++++++-------------------------
 1 file changed, 75 insertions(+), 75 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9bc84a2..df4c897 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10945,7 +10945,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_WIPHY,
 		.doit = nl80211_set_wiphy,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_RTNL,
 	},
 	{
@@ -10961,7 +10961,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_INTERFACE,
 		.doit = nl80211_set_interface,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -10969,7 +10969,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_NEW_INTERFACE,
 		.doit = nl80211_new_interface,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -10977,7 +10977,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DEL_INTERFACE,
 		.doit = nl80211_del_interface,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -10985,7 +10985,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_GET_KEY,
 		.doit = nl80211_get_key,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -10993,7 +10993,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_KEY,
 		.doit = nl80211_set_key,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL |
 				  NL80211_FLAG_CLEAR_SKB,
@@ -11002,7 +11002,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_NEW_KEY,
 		.doit = nl80211_new_key,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL |
 				  NL80211_FLAG_CLEAR_SKB,
@@ -11011,14 +11011,14 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DEL_KEY,
 		.doit = nl80211_del_key,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
 	{
 		.cmd = NL80211_CMD_SET_BEACON,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.doit = nl80211_set_beacon,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
@@ -11026,7 +11026,7 @@ static const struct genl_ops nl80211_ops[] = {
 	{
 		.cmd = NL80211_CMD_START_AP,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.doit = nl80211_start_ap,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
@@ -11034,7 +11034,7 @@ static const struct genl_ops nl80211_ops[] = {
 	{
 		.cmd = NL80211_CMD_STOP_AP,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.doit = nl80211_stop_ap,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
@@ -11051,7 +11051,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_STATION,
 		.doit = nl80211_set_station,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11059,7 +11059,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_NEW_STATION,
 		.doit = nl80211_new_station,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11067,7 +11067,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DEL_STATION,
 		.doit = nl80211_del_station,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11076,7 +11076,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.doit = nl80211_get_mpath,
 		.dumpit = nl80211_dump_mpath,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11085,7 +11085,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.doit = nl80211_get_mpp,
 		.dumpit = nl80211_dump_mpp,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11093,7 +11093,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_MPATH,
 		.doit = nl80211_set_mpath,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11101,7 +11101,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_NEW_MPATH,
 		.doit = nl80211_new_mpath,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11109,7 +11109,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DEL_MPATH,
 		.doit = nl80211_del_mpath,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11117,7 +11117,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_BSS,
 		.doit = nl80211_set_bss,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11156,7 +11156,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_MESH_CONFIG,
 		.doit = nl80211_update_mesh_config,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11164,7 +11164,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_TRIGGER_SCAN,
 		.doit = nl80211_trigger_scan,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11185,7 +11185,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_START_SCHED_SCAN,
 		.doit = nl80211_start_sched_scan,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11193,7 +11193,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_STOP_SCHED_SCAN,
 		.doit = nl80211_stop_sched_scan,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11201,7 +11201,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_AUTHENTICATE,
 		.doit = nl80211_authenticate,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL |
 				  NL80211_FLAG_CLEAR_SKB,
@@ -11210,7 +11210,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_ASSOCIATE,
 		.doit = nl80211_associate,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11218,7 +11218,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DEAUTHENTICATE,
 		.doit = nl80211_deauthenticate,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11226,7 +11226,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DISASSOCIATE,
 		.doit = nl80211_disassociate,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11234,7 +11234,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_JOIN_IBSS,
 		.doit = nl80211_join_ibss,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11242,7 +11242,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_LEAVE_IBSS,
 		.doit = nl80211_leave_ibss,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11252,7 +11252,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.doit = nl80211_testmode_do,
 		.dumpit = nl80211_testmode_dump,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11261,7 +11261,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_CONNECT,
 		.doit = nl80211_connect,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11269,7 +11269,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DISCONNECT,
 		.doit = nl80211_disconnect,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11277,7 +11277,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_WIPHY_NETNS,
 		.doit = nl80211_wiphy_netns,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11290,7 +11290,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_PMKSA,
 		.doit = nl80211_setdel_pmksa,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11298,7 +11298,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DEL_PMKSA,
 		.doit = nl80211_setdel_pmksa,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11306,7 +11306,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_FLUSH_PMKSA,
 		.doit = nl80211_flush_pmksa,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11314,7 +11314,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_REMAIN_ON_CHANNEL,
 		.doit = nl80211_remain_on_channel,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11322,7 +11322,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
 		.doit = nl80211_cancel_remain_on_channel,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11330,7 +11330,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_TX_BITRATE_MASK,
 		.doit = nl80211_set_tx_bitrate_mask,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11338,7 +11338,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_REGISTER_FRAME,
 		.doit = nl80211_register_mgmt,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11346,7 +11346,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_FRAME,
 		.doit = nl80211_tx_mgmt,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11354,7 +11354,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
 		.doit = nl80211_tx_mgmt_cancel_wait,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11362,7 +11362,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_POWER_SAVE,
 		.doit = nl80211_set_power_save,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11378,7 +11378,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_CQM,
 		.doit = nl80211_set_cqm,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11386,7 +11386,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_CHANNEL,
 		.doit = nl80211_set_channel,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11394,7 +11394,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_WDS_PEER,
 		.doit = nl80211_set_wds_peer,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11402,7 +11402,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_JOIN_MESH,
 		.doit = nl80211_join_mesh,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11410,7 +11410,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_LEAVE_MESH,
 		.doit = nl80211_leave_mesh,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11418,7 +11418,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_JOIN_OCB,
 		.doit = nl80211_join_ocb,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11426,7 +11426,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_LEAVE_OCB,
 		.doit = nl80211_leave_ocb,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11443,7 +11443,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_WOWLAN,
 		.doit = nl80211_set_wowlan,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11452,7 +11452,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
 		.doit = nl80211_set_rekey_data,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL |
 				  NL80211_FLAG_CLEAR_SKB,
@@ -11461,7 +11461,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_TDLS_MGMT,
 		.doit = nl80211_tdls_mgmt,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11469,7 +11469,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_TDLS_OPER,
 		.doit = nl80211_tdls_oper,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11477,7 +11477,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_UNEXPECTED_FRAME,
 		.doit = nl80211_register_unexpected_frame,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11485,7 +11485,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_PROBE_CLIENT,
 		.doit = nl80211_probe_client,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11493,7 +11493,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_REGISTER_BEACONS,
 		.doit = nl80211_register_beacons,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11501,7 +11501,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_NOACK_MAP,
 		.doit = nl80211_set_noack_map,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11509,7 +11509,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_START_P2P_DEVICE,
 		.doit = nl80211_start_p2p_device,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11517,7 +11517,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_STOP_P2P_DEVICE,
 		.doit = nl80211_stop_p2p_device,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11525,7 +11525,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_MCAST_RATE,
 		.doit = nl80211_set_mcast_rate,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11533,7 +11533,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_MAC_ACL,
 		.doit = nl80211_set_mac_acl,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11541,7 +11541,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_RADAR_DETECT,
 		.doit = nl80211_start_radar_detection,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11554,7 +11554,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_UPDATE_FT_IES,
 		.doit = nl80211_update_ft_ies,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11562,7 +11562,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_CRIT_PROTOCOL_START,
 		.doit = nl80211_crit_protocol_start,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11570,7 +11570,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
 		.doit = nl80211_crit_protocol_stop,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11585,7 +11585,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_COALESCE,
 		.doit = nl80211_set_coalesce,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11593,7 +11593,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_CHANNEL_SWITCH,
 		.doit = nl80211_channel_switch,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11602,7 +11602,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.doit = nl80211_vendor_cmd,
 		.dumpit = nl80211_vendor_cmd_dump,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_WIPHY |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11610,7 +11610,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_SET_QOS_MAP,
 		.doit = nl80211_set_qos_map,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11618,7 +11618,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_ADD_TX_TS,
 		.doit = nl80211_add_tx_ts,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11626,7 +11626,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_DEL_TX_TS,
 		.doit = nl80211_del_tx_ts,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11634,7 +11634,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_TDLS_CHANNEL_SWITCH,
 		.doit = nl80211_tdls_channel_switch,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
@@ -11642,7 +11642,7 @@ static const struct genl_ops nl80211_ops[] = {
 		.cmd = NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
 		.doit = nl80211_tdls_cancel_channel_switch,
 		.policy = nl80211_policy,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/2] mac80211_hwsim: Allow managing radios from non-initial namespaces
From: Martin Willi @ 2016-05-03  6:53 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, netdev
In-Reply-To: <1462258398-6749-1-git-send-email-martin@strongswan.org>

While wiphys can be moved into network namespaces over nl80211, the
creation and removal of hwsim radios is currently limited to the initial
namespace. This patch allows management of namespaced radios from the
owning namespace by setting genetlink netnsok.

To prevent two arbitrary namespaces from communicating over the simulated
shared medium, radios are separated by netgroups. Each radio created in
the same namespace lives in the same netgroup and hence can communicate
with other radios in that group. When moving radios to other namespaces,
the netgroup is preserved, so two radios having the same netgroup can
communicate even if not in the same namespace; This allows a controlling
namespace to create radios and move them to other namespaces for
communication.

Signed-off-by: Martin Willi <martin@strongswan.org>
---
 drivers/net/wireless/mac80211_hwsim.c | 88 +++++++++++++++++++++++++++++++++--
 1 file changed, 85 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index c757f14..91bd440 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -30,6 +30,8 @@
 #include <linux/module.h>
 #include <linux/ktime.h>
 #include <net/genetlink.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
 #include "mac80211_hwsim.h"
 
 #define WARN_QUEUE 100
@@ -39,6 +41,7 @@ MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
 MODULE_LICENSE("GPL");
 
+static unsigned int hwsim_net_id;
 static u32 wmediumd_portid;
 
 static int radios = 2;
@@ -526,6 +529,9 @@ struct mac80211_hwsim_data {
 	 */
 	u64 group;
 
+	/* group shared by radios created in the same netns */
+	int netgroup;
+
 	int power_level;
 
 	/* difference between this hw's clock and the real clock, in usecs */
@@ -568,6 +574,7 @@ static struct genl_family hwsim_genl_family = {
 	.name = "MAC80211_HWSIM",
 	.version = 1,
 	.maxattr = HWSIM_ATTR_MAX,
+	.netnsok = true,
 };
 
 enum hwsim_multicast_groups {
@@ -1202,6 +1209,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
 		if (!(data->group & data2->group))
 			continue;
 
+		if (data->netgroup != data2->netgroup)
+			continue;
+
 		if (!hwsim_chans_compat(chan, data2->tmp_chan) &&
 		    !hwsim_chans_compat(chan, data2->channel)) {
 			ieee80211_iterate_active_interfaces_atomic(
@@ -2348,6 +2358,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 	struct mac80211_hwsim_data *data;
 	struct ieee80211_hw *hw;
 	enum nl80211_band band;
+	struct net *net;
 	const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
 	int idx;
 
@@ -2366,6 +2377,13 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 		err = -ENOMEM;
 		goto failed;
 	}
+
+	if (info)
+		net = genl_info_net(info);
+	else
+		net = &init_net;
+	wiphy_net_set(hw->wiphy, net);
+
 	data = hw->priv;
 	data->hw = hw;
 
@@ -2541,6 +2559,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
 	data->group = 1;
 	mutex_init(&data->mutex);
 
+	data->netgroup = *(int *)net_generic(net, hwsim_net_id);
+
 	/* Enable frame retransmissions for lossy channels */
 	hw->max_rates = 4;
 	hw->max_rate_tries = 11;
@@ -3013,6 +3033,9 @@ static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
 				continue;
 		}
 
+		if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info)))
+			continue;
+
 		list_del(&data->list);
 		spin_unlock_bh(&hwsim_radio_lock);
 		mac80211_hwsim_del_radio(data, wiphy_name(data->hw->wiphy),
@@ -3039,6 +3062,9 @@ static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
 		if (data->idx != idx)
 			continue;
 
+		if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info)))
+			continue;
+
 		skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 		if (!skb) {
 			res = -ENOMEM;
@@ -3078,6 +3104,9 @@ static int hwsim_dump_radio_nl(struct sk_buff *skb,
 		if (data->idx < idx)
 			continue;
 
+		if (!net_eq(wiphy_net(data->hw->wiphy), sock_net(skb->sk)))
+			continue;
+
 		res = mac80211_hwsim_get_radio(skb, data,
 					       NETLINK_CB(cb->skb).portid,
 					       cb->nlh->nlmsg_seq, cb,
@@ -3117,13 +3146,13 @@ static const struct genl_ops hwsim_ops[] = {
 		.cmd = HWSIM_CMD_NEW_RADIO,
 		.policy = hwsim_genl_policy,
 		.doit = hwsim_new_radio_nl,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 	},
 	{
 		.cmd = HWSIM_CMD_DEL_RADIO,
 		.policy = hwsim_genl_policy,
 		.doit = hwsim_del_radio_nl,
-		.flags = GENL_ADMIN_PERM,
+		.flags = GENL_UNS_ADMIN_PERM,
 	},
 	{
 		.cmd = HWSIM_CMD_GET_RADIO,
@@ -3205,6 +3234,52 @@ failure:
 	return -EINVAL;
 }
 
+static __net_init int hwsim_init_net(struct net *net)
+{
+	struct mac80211_hwsim_data *data;
+	bool exists = true;
+	int netgroup = 0;
+
+	spin_lock_bh(&hwsim_radio_lock);
+	while (exists) {
+		exists = false;
+		list_for_each_entry(data, &hwsim_radios, list) {
+			if (netgroup == data->netgroup) {
+				exists = true;
+				netgroup++;
+				break;
+			}
+		}
+	}
+	spin_unlock_bh(&hwsim_radio_lock);
+
+	*(int *)net_generic(net, hwsim_net_id) = netgroup;
+
+	return 0;
+}
+
+static void __net_exit hwsim_exit_net(struct net *net)
+{
+	struct mac80211_hwsim_data *entry, *tmp;
+
+	spin_lock_bh(&hwsim_radio_lock);
+	list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) {
+		if (net_eq(wiphy_net(entry->hw->wiphy), net)) {
+			list_del(&entry->list);
+			INIT_WORK(&entry->destroy_work, destroy_radio);
+			schedule_work(&entry->destroy_work);
+		}
+	}
+	spin_unlock_bh(&hwsim_radio_lock);
+}
+
+static struct pernet_operations hwsim_net_ops = {
+	.init = hwsim_init_net,
+	.exit = hwsim_exit_net,
+	.id   = &hwsim_net_id,
+	.size = sizeof(int),
+};
+
 static void hwsim_exit_netlink(void)
 {
 	/* unregister the notifier */
@@ -3241,10 +3316,14 @@ static int __init init_mac80211_hwsim(void)
 	spin_lock_init(&hwsim_radio_lock);
 	INIT_LIST_HEAD(&hwsim_radios);
 
-	err = platform_driver_register(&mac80211_hwsim_driver);
+	err = register_pernet_device(&hwsim_net_ops);
 	if (err)
 		return err;
 
+	err = platform_driver_register(&mac80211_hwsim_driver);
+	if (err)
+		goto out_unregister_pernet;
+
 	hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
 	if (IS_ERR(hwsim_class)) {
 		err = PTR_ERR(hwsim_class);
@@ -3362,6 +3441,8 @@ out_free_radios:
 	mac80211_hwsim_free();
 out_unregister_driver:
 	platform_driver_unregister(&mac80211_hwsim_driver);
+out_unregister_pernet:
+	unregister_pernet_device(&hwsim_net_ops);
 	return err;
 }
 module_init(init_mac80211_hwsim);
@@ -3375,5 +3456,6 @@ static void __exit exit_mac80211_hwsim(void)
 	mac80211_hwsim_free();
 	unregister_netdev(hwsim_mon);
 	platform_driver_unregister(&mac80211_hwsim_driver);
+	unregister_pernet_device(&hwsim_net_ops);
 }
 module_exit(exit_mac80211_hwsim);
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH 2/2] mac80211_hwsim: Allow managing radios from non-initial namespaces
From: Johannes Berg @ 2016-05-03  6:56 UTC (permalink / raw)
  To: Martin Willi; +Cc: linux-wireless, netdev
In-Reply-To: <1462258398-6749-3-git-send-email-martin@strongswan.org>

On Tue, 2016-05-03 at 08:53 +0200, Martin Willi wrote:
> While wiphys can be moved into network namespaces over nl80211, the
> creation and removal of hwsim radios is currently limited to the
> initial namespace. This patch allows management of namespaced radios
> from the owning namespace by setting genetlink netnsok.

Interesting.

> To prevent two arbitrary namespaces from communicating over the
> simulated
> shared medium, radios are separated by netgroups. Each radio created
> in
> the same namespace lives in the same netgroup and hence can
> communicate
> with other radios in that group. When moving radios to other
> namespaces,
> the netgroup is preserved, so two radios having the same netgroup can
> communicate even if not in the same namespace; This allows a
> controlling
> namespace to create radios and move them to other namespaces for
> communication.

Neat.

I'm curious what the use case is?

I'll need some time to review it, it'll likely have to wait until next
week given our holiday here on Thursday (and I'm also off work
tomorrow/Friday)

johannes

^ permalink raw reply

* [PATCH 0/2] wireless: Allow wiphy/hwsim management from user namespaces
From: Martin Willi @ 2016-05-03  6:53 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA

This patch set enables user namespaces having CAP_NET_ADMIN to manage
wiphy devices and create/destroy hwsim radios.

The first patch allows a caller from a non-initial user namespace to run
privileged nl80211 phy/dev operations. The second patch enables hwsim
radio management over Netlink from such namespaces. Together, with these
patches an unprivileged test environment can create user/network
namespaces and set up abitrary simulated wireless networks.

Martin Willi (2):
  nl80211: Allow privileged operations from user namespaces
  mac80211_hwsim: Allow managing radios from non-initial namespaces

 drivers/net/wireless/mac80211_hwsim.c |  88 +++++++++++++++++++-
 net/wireless/nl80211.c                | 150 +++++++++++++++++-----------------
 2 files changed, 160 insertions(+), 78 deletions(-)

--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Listing from maryjanesogrub
From: maryjanesogrub @ 2016-05-03  5:13 UTC (permalink / raw)
  To: mrechberger, shdl, heikki.orsila, rjkm, nagendra_tomar, eparis,
	eric.rannaud, netdev, bcollins, linux1394-devel

Your friend, maryjanesogrub, has sent along the following link:
http://www.midwestrealty.net/listingview.php?listingID=1128

Comment:
JOB POSITION AVAILABLE - APPLY NOW!
WE'RE HIRING: Data Entry Workers Earn $500 up to $1000 Daily 
(No Experience Required)

Good Day,

You recently expressed an interest in obtaining a
position you could do from the comfort of your own home.
I am happy to let you know that I found a great company
that will help you get started working online.

Visit our website here:

http://link.limo/1jqz

The scope of the work is very simple.
You can work as little or as much as you want
depending on how much you want your paycheck to be

No background experience is needed because you
will be given a detailed step-by-step training in
all the job fields along with all the resources you
needed to help you get started immediately.

Visit our website here:

http://link.limo/1jqz

If you're serious about this position, though,
then I encourage you to take action immediately.
We only have a few openings left, and we expect them
to fill up fast. This really is a great opportunity!

THANKS

^ permalink raw reply

* Re: off-by-one in DecodeQ931
From: Toby DiPasquale @ 2016-05-03  5:12 UTC (permalink / raw)
  To: Florian Westphal
  Cc: pablo, Patrick McHardy, kadlec, davem, netfilter-devel, coreteam,
	netdev
In-Reply-To: <20160425152905.GA8621@strlen.de>

On Mon, Apr 25, 2016 at 11:29 AM, Florian Westphal <fw@strlen.de> wrote:
> -> sz (size_t) will underflow here
>
> I'd suggest to change the if (sz < 1) to if (sz < 2) to
> resolve this, the while loop below has to be taken anyway.

Thanks, Florian! Updated patch below:

Signed-off-by: Toby DiPasquale <toby@cbcg.net>

diff --git a/net/netfilter/nf_conntrack_h323_asn1.c
b/net/netfilter/nf_conntrack_h323_asn1.c
index bcd5ed6..89b2e46 100644
--- a/net/netfilter/nf_conntrack_h323_asn1.c
+++ b/net/netfilter/nf_conntrack_h323_asn1.c
@@ -846,9 +846,10 @@ int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
        sz -= len;

        /* Message Type */
-       if (sz < 1)
+       if (sz < 2)
                return H323_ERROR_BOUND;
        q931->MessageType = *p++;
+       sz--;
        PRINT("MessageType = %02X\n", q931->MessageType);
        if (*p & 0x80) {
                p++;

^ permalink raw reply related

* [REGRESSION] asix: Lots of asix_rx_fixup() errors and slow transmissions
From: John Stultz @ 2016-05-03  4:55 UTC (permalink / raw)
  To: lkml
  Cc: Dean Jenkins, Mark Craske, David S. Miller, YongQin Liu,
	Guodong Xu, linux-usb, netdev, Ivan Vecera, David B. Robins

In testing with HiKey, we found that since commit 3f30b158eba5c60
(asix: On RX avoid creating bad Ethernet frames), we're seeing lots of
noise during network transfers:

[  239.027993] asix 1-1.1:1.0 eth0: asix_rx_fixup() Data Header
synchronisation was lost, remaining 988
[  239.037310] asix 1-1.1:1.0 eth0: asix_rx_fixup() Bad Header Length
0x54ebb5ec, offset 4
[  239.045519] asix 1-1.1:1.0 eth0: asix_rx_fixup() Bad Header Length
0xcdffe7a2, offset 4
[  239.275044] asix 1-1.1:1.0 eth0: asix_rx_fixup() Data Header
synchronisation was lost, remaining 988
[  239.284355] asix 1-1.1:1.0 eth0: asix_rx_fixup() Bad Header Length
0x1d36f59d, offset 4
[  239.292541] asix 1-1.1:1.0 eth0: asix_rx_fixup() Bad Header Length
0xaef3c1e9, offset 4
[  239.518996] asix 1-1.1:1.0 eth0: asix_rx_fixup() Data Header
synchronisation was lost, remaining 988
[  239.528300] asix 1-1.1:1.0 eth0: asix_rx_fixup() Bad Header Length
0x2881912, offset 4
[  239.536413] asix 1-1.1:1.0 eth0: asix_rx_fixup() Bad Header Length
0x5638f7e2, offset 4


And network throughput ends up being pretty bursty and slow with a
overall throughput of at best ~30kB/s.

Looking through the commits since the v4.1 kernel where we didn't see
this, I narrowed the regression down, and reverting the following two
commits seems to avoid the problem:

6a570814cd430fa5ef4f278e8046dcf12ee63f13 asix: Continue processing URB
if no RX netdev buffer
3f30b158eba5c604b6e0870027eef5d19fc9271d asix: On RX avoid creating
bad Ethernet frames

With these reverted, we don't see all the error messages, and we see
better ~1.1MB/s throughput (I've got a mouse plugged in, so I think
the usb host is only running at "full-speed" mode here).

This worries me some, as the patches seem to describe trying to fix
the issue they seem to cause, so I suspect a revert isn't the correct
solution, but am not sure why we're having such trouble and the patch
authors did not.  I'd be happy to do further testing of patches if
folks have any ideas.

Originally Reported-by: Yongqin Liu <yongqin.liu@linaro.org>

thanks
-john

^ permalink raw reply

* Re: [PATCH net-next] tcp: guarantee forward progress in tcp_sendmsg()
From: Soheil Hassas Yeganeh @ 2016-05-03  4:53 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Eric Dumazet, David Miller, netdev, Alexei Starovoitov,
	Marcelo Ricardo Leitner
In-Reply-To: <1462250965.5535.286.camel@edumazet-glaptop3.roam.corp.google.com>

On Tue, May 3, 2016 at 12:49 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> Under high rx pressure, it is possible tcp_sendmsg() never has a
> chance to allocate an skb and loop forever as sk_flush_backlog()
> would always return true.
>
> Fix this by calling sk_flush_backlog() only if one skb had been
> allocated and filled before last backlog check.
>
> Fixes: d41a69f1d390 ("tcp: make tcp_sendmsg() aware of socket backlog")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Soheil Hassas Yeganeh <soheil@google.com>
> ---
>  net/ipv4/tcp.c |    7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index b945c2b046c5ead5503505f250c3c67761b284ae..5c7ed147449c1b7ba029b12e033ad779a631460a 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -1084,6 +1084,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
>         struct sockcm_cookie sockc;
>         int flags, err, copied = 0;
>         int mss_now = 0, size_goal, copied_syn = 0;
> +       bool process_backlog = false;
>         bool sg;
>         long timeo;
>
> @@ -1167,9 +1168,10 @@ new_segment:
>                         if (!sk_stream_memory_free(sk))
>                                 goto wait_for_sndbuf;
>
> -                       if (sk_flush_backlog(sk))
> +                       if (process_backlog && sk_flush_backlog(sk)) {
> +                               process_backlog = false;
>                                 goto restart;
> -
> +                       }
>                         skb = sk_stream_alloc_skb(sk,
>                                                   select_size(sk, sg),
>                                                   sk->sk_allocation,
> @@ -1177,6 +1179,7 @@ new_segment:
>                         if (!skb)
>                                 goto wait_for_memory;
>
> +                       process_backlog = true;
>                         /*
>                          * Check whether we can use HW checksum.
>                          */
>
>

Nice catch! Thanks.

^ permalink raw reply

* [PATCH net-next] tcp: guarantee forward progress in tcp_sendmsg()
From: Eric Dumazet @ 2016-05-03  4:49 UTC (permalink / raw)
  To: Eric Dumazet, David Miller
  Cc: netdev, Soheil Hassas Yeganeh, Alexei Starovoitov,
	Marcelo Ricardo Leitner
In-Reply-To: <1461964613-4872-8-git-send-email-edumazet@google.com>

From: Eric Dumazet <edumazet@google.com>

Under high rx pressure, it is possible tcp_sendmsg() never has a
chance to allocate an skb and loop forever as sk_flush_backlog()
would always return true.

Fix this by calling sk_flush_backlog() only if one skb had been
allocated and filled before last backlog check.

Fixes: d41a69f1d390 ("tcp: make tcp_sendmsg() aware of socket backlog")
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/ipv4/tcp.c |    7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b945c2b046c5ead5503505f250c3c67761b284ae..5c7ed147449c1b7ba029b12e033ad779a631460a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1084,6 +1084,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 	struct sockcm_cookie sockc;
 	int flags, err, copied = 0;
 	int mss_now = 0, size_goal, copied_syn = 0;
+	bool process_backlog = false;
 	bool sg;
 	long timeo;
 
@@ -1167,9 +1168,10 @@ new_segment:
 			if (!sk_stream_memory_free(sk))
 				goto wait_for_sndbuf;
 
-			if (sk_flush_backlog(sk))
+			if (process_backlog && sk_flush_backlog(sk)) {
+				process_backlog = false;
 				goto restart;
-
+			}
 			skb = sk_stream_alloc_skb(sk,
 						  select_size(sk, sg),
 						  sk->sk_allocation,
@@ -1177,6 +1179,7 @@ new_segment:
 			if (!skb)
 				goto wait_for_memory;
 
+			process_backlog = true;
 			/*
 			 * Check whether we can use HW checksum.
 			 */

^ permalink raw reply related

* [PATCH net-next v2] ipv6: add new struct ipcm6_cookie
From: Wei Wang @ 2016-05-03  4:40 UTC (permalink / raw)
  To: netdev; +Cc: Wei Wang

From: Wei Wang <weiwan@google.com>

In the sendmsg function of UDP, raw, ICMP and l2tp sockets, we use local
variables like hlimits, tclass, opt and dontfrag and pass them to corresponding
functions like ip6_make_skb, ip6_append_data and xxx_push_pending_frames.
This is not a good practice and makes it hard to add new parameters.
This fix introduces a new struct ipcm6_cookie similar to ipcm_cookie in
ipv4 and include the above mentioned variables. And we only pass the
pointer to this structure to corresponding functions. This makes it easier
to add new parameters in the future and makes the function cleaner.

Signed-off-by: Wei Wang <weiwan@google.com>
---
 include/net/ipv6.h       | 18 ++++++++++++------
 include/net/transp_v6.h  |  3 +--
 net/ipv6/datagram.c      | 13 ++++++-------
 net/ipv6/icmp.c          | 28 ++++++++++++++++------------
 net/ipv6/ip6_flowlabel.c |  6 +++---
 net/ipv6/ip6_output.c    | 42 ++++++++++++++++++++----------------------
 net/ipv6/ipv6_sockglue.c |  6 +++---
 net/ipv6/ping.c          | 12 +++++++-----
 net/ipv6/raw.c           | 33 ++++++++++++++++++---------------
 net/ipv6/udp.c           | 38 +++++++++++++++++++-------------------
 net/l2tp/l2tp_ip6.c      | 33 ++++++++++++++++++---------------
 11 files changed, 123 insertions(+), 109 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 415213d..11a0452 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -251,6 +251,13 @@ struct ipv6_fl_socklist {
 	struct rcu_head			rcu;
 };
 
+struct ipcm6_cookie {
+	__s16 hlimit;
+	__s16 tclass;
+	__s8  dontfrag;
+	struct ipv6_txoptions *opt;
+};
+
 static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
 {
 	struct ipv6_txoptions *opt;
@@ -863,9 +870,9 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr);
 int ip6_append_data(struct sock *sk,
 		    int getfrag(void *from, char *to, int offset, int len,
 				int odd, struct sk_buff *skb),
-		    void *from, int length, int transhdrlen, int hlimit,
-		    int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
-		    struct rt6_info *rt, unsigned int flags, int dontfrag,
+		    void *from, int length, int transhdrlen,
+		    struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
+		    struct rt6_info *rt, unsigned int flags,
 		    const struct sockcm_cookie *sockc);
 
 int ip6_push_pending_frames(struct sock *sk);
@@ -881,9 +888,8 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
 			     int getfrag(void *from, char *to, int offset,
 					 int len, int odd, struct sk_buff *skb),
 			     void *from, int length, int transhdrlen,
-			     int hlimit, int tclass, struct ipv6_txoptions *opt,
-			     struct flowi6 *fl6, struct rt6_info *rt,
-			     unsigned int flags, int dontfrag,
+			     struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
+			     struct rt6_info *rt, unsigned int flags,
 			     const struct sockcm_cookie *sockc);
 
 static inline struct sk_buff *ip6_finish_skb(struct sock *sk)
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 2b1c345..276f976 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -41,8 +41,7 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
 				    struct sk_buff *skb);
 
 int ip6_datagram_send_ctl(struct net *net, struct sock *sk, struct msghdr *msg,
-			  struct flowi6 *fl6, struct ipv6_txoptions *opt,
-			  int *hlimit, int *tclass, int *dontfrag,
+			  struct flowi6 *fl6, struct ipcm6_cookie *ipc6,
 			  struct sockcm_cookie *sockc);
 
 void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp,
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index ea9ee5c..00d0c29 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -727,14 +727,13 @@ EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl);
 
 int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
 			  struct msghdr *msg, struct flowi6 *fl6,
-			  struct ipv6_txoptions *opt,
-			  int *hlimit, int *tclass, int *dontfrag,
-			  struct sockcm_cookie *sockc)
+			  struct ipcm6_cookie *ipc6, struct sockcm_cookie *sockc)
 {
 	struct in6_pktinfo *src_info;
 	struct cmsghdr *cmsg;
 	struct ipv6_rt_hdr *rthdr;
 	struct ipv6_opt_hdr *hdr;
+	struct ipv6_txoptions *opt = ipc6->opt;
 	int len;
 	int err = 0;
 
@@ -953,8 +952,8 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
 				goto exit_f;
 			}
 
-			*hlimit = *(int *)CMSG_DATA(cmsg);
-			if (*hlimit < -1 || *hlimit > 0xff) {
+			ipc6->hlimit = *(int *)CMSG_DATA(cmsg);
+			if (ipc6->hlimit < -1 || ipc6->hlimit > 0xff) {
 				err = -EINVAL;
 				goto exit_f;
 			}
@@ -974,7 +973,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
 				goto exit_f;
 
 			err = 0;
-			*tclass = tc;
+			ipc6->tclass = tc;
 
 			break;
 		    }
@@ -992,7 +991,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
 				goto exit_f;
 
 			err = 0;
-			*dontfrag = df;
+			ipc6->dontfrag = df;
 
 			break;
 		    }
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 23b9a4c..9554b99 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -401,10 +401,10 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
 	struct flowi6 fl6;
 	struct icmpv6_msg msg;
 	struct sockcm_cookie sockc_unused = {0};
+	struct ipcm6_cookie ipc6;
 	int iif = 0;
 	int addr_type = 0;
 	int len;
-	int hlimit;
 	int err = 0;
 	u32 mark = IP6_REPLY_MARK(net, skb->mark);
 
@@ -507,7 +507,10 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
 	if (IS_ERR(dst))
 		goto out;
 
-	hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	ipc6.tclass = np->tclass;
+	ipc6.dontfrag = np->dontfrag;
+	ipc6.opt = NULL;
 
 	msg.skb = skb;
 	msg.offset = skb_network_offset(skb);
@@ -526,9 +529,9 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
 
 	err = ip6_append_data(sk, icmpv6_getfrag, &msg,
 			      len + sizeof(struct icmp6hdr),
-			      sizeof(struct icmp6hdr), hlimit,
-			      np->tclass, NULL, &fl6, (struct rt6_info *)dst,
-			      MSG_DONTWAIT, np->dontfrag, &sockc_unused);
+			      sizeof(struct icmp6hdr),
+			      &ipc6, &fl6, (struct rt6_info *)dst,
+			      MSG_DONTWAIT, &sockc_unused);
 	if (err) {
 		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
 		ip6_flush_pending_frames(sk);
@@ -563,9 +566,8 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 	struct flowi6 fl6;
 	struct icmpv6_msg msg;
 	struct dst_entry *dst;
+	struct ipcm6_cookie ipc6;
 	int err = 0;
-	int hlimit;
-	u8 tclass;
 	u32 mark = IP6_REPLY_MARK(net, skb->mark);
 	struct sockcm_cookie sockc_unused = {0};
 
@@ -607,19 +609,21 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 	if (IS_ERR(dst))
 		goto out;
 
-	hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
-
 	idev = __in6_dev_get(skb->dev);
 
 	msg.skb = skb;
 	msg.offset = 0;
 	msg.type = ICMPV6_ECHO_REPLY;
 
-	tclass = ipv6_get_dsfield(ipv6_hdr(skb));
+	ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb));
+	ipc6.dontfrag = np->dontfrag;
+	ipc6.opt = NULL;
+
 	err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
-				sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl6,
+				sizeof(struct icmp6hdr), &ipc6, &fl6,
 				(struct rt6_info *)dst, MSG_DONTWAIT,
-				np->dontfrag, &sockc_unused);
+				&sockc_unused);
 
 	if (err) {
 		__ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS);
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 35d3ddc..b912f0d 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -373,7 +373,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
 		struct msghdr msg;
 		struct flowi6 flowi6;
 		struct sockcm_cookie sockc_junk;
-		int junk;
+		struct ipcm6_cookie ipc6;
 
 		err = -ENOMEM;
 		fl->opt = kmalloc(sizeof(*fl->opt) + olen, GFP_KERNEL);
@@ -390,8 +390,8 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
 		msg.msg_control = (void *)(fl->opt+1);
 		memset(&flowi6, 0, sizeof(flowi6));
 
-		err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt,
-					    &junk, &junk, &junk, &sockc_junk);
+		ipc6.opt = fl->opt;
+		err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, &ipc6, &sockc_junk);
 		if (err)
 			goto done;
 		err = -EINVAL;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 2b3ffc5..cbf127a 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1182,12 +1182,12 @@ static void ip6_append_data_mtu(unsigned int *mtu,
 }
 
 static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
-			  struct inet6_cork *v6_cork,
-			  int hlimit, int tclass, struct ipv6_txoptions *opt,
+			  struct inet6_cork *v6_cork, struct ipcm6_cookie *ipc6,
 			  struct rt6_info *rt, struct flowi6 *fl6)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	unsigned int mtu;
+	struct ipv6_txoptions *opt = ipc6->opt;
 
 	/*
 	 * setup for corking
@@ -1229,8 +1229,8 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
 	dst_hold(&rt->dst);
 	cork->base.dst = &rt->dst;
 	cork->fl.u.ip6 = *fl6;
-	v6_cork->hop_limit = hlimit;
-	v6_cork->tclass = tclass;
+	v6_cork->hop_limit = ipc6->hlimit;
+	v6_cork->tclass = ipc6->tclass;
 	if (rt->dst.flags & DST_XFRM_TUNNEL)
 		mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
 		      rt->dst.dev->mtu : dst_mtu(&rt->dst);
@@ -1258,7 +1258,7 @@ static int __ip6_append_data(struct sock *sk,
 			     int getfrag(void *from, char *to, int offset,
 					 int len, int odd, struct sk_buff *skb),
 			     void *from, int length, int transhdrlen,
-			     unsigned int flags, int dontfrag,
+			     unsigned int flags, struct ipcm6_cookie *ipc6,
 			     const struct sockcm_cookie *sockc)
 {
 	struct sk_buff *skb, *skb_prev = NULL;
@@ -1298,7 +1298,7 @@ static int __ip6_append_data(struct sock *sk,
 		      sizeof(struct frag_hdr) : 0) +
 		     rt->rt6i_nfheader_len;
 
-	if (cork->length + length > mtu - headersize && dontfrag &&
+	if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
 	    (sk->sk_protocol == IPPROTO_UDP ||
 	     sk->sk_protocol == IPPROTO_RAW)) {
 		ipv6_local_rxpmtu(sk, fl6, mtu - headersize +
@@ -1564,9 +1564,9 @@ error:
 int ip6_append_data(struct sock *sk,
 		    int getfrag(void *from, char *to, int offset, int len,
 				int odd, struct sk_buff *skb),
-		    void *from, int length, int transhdrlen, int hlimit,
-		    int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
-		    struct rt6_info *rt, unsigned int flags, int dontfrag,
+		    void *from, int length, int transhdrlen,
+		    struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
+		    struct rt6_info *rt, unsigned int flags,
 		    const struct sockcm_cookie *sockc)
 {
 	struct inet_sock *inet = inet_sk(sk);
@@ -1580,12 +1580,12 @@ int ip6_append_data(struct sock *sk,
 		/*
 		 * setup for corking
 		 */
-		err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit,
-				     tclass, opt, rt, fl6);
+		err = ip6_setup_cork(sk, &inet->cork, &np->cork,
+				     ipc6, rt, fl6);
 		if (err)
 			return err;
 
-		exthdrlen = (opt ? opt->opt_flen : 0);
+		exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
 		length += exthdrlen;
 		transhdrlen += exthdrlen;
 	} else {
@@ -1595,8 +1595,7 @@ int ip6_append_data(struct sock *sk,
 
 	return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base,
 				 &np->cork, sk_page_frag(sk), getfrag,
-				 from, length, transhdrlen, flags, dontfrag,
-				 sockc);
+				 from, length, transhdrlen, flags, ipc6, sockc);
 }
 EXPORT_SYMBOL_GPL(ip6_append_data);
 
@@ -1752,15 +1751,14 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
 			     int getfrag(void *from, char *to, int offset,
 					 int len, int odd, struct sk_buff *skb),
 			     void *from, int length, int transhdrlen,
-			     int hlimit, int tclass,
-			     struct ipv6_txoptions *opt, struct flowi6 *fl6,
+			     struct ipcm6_cookie *ipc6, struct flowi6 *fl6,
 			     struct rt6_info *rt, unsigned int flags,
-			     int dontfrag, const struct sockcm_cookie *sockc)
+			     const struct sockcm_cookie *sockc)
 {
 	struct inet_cork_full cork;
 	struct inet6_cork v6_cork;
 	struct sk_buff_head queue;
-	int exthdrlen = (opt ? opt->opt_flen : 0);
+	int exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0);
 	int err;
 
 	if (flags & MSG_PROBE)
@@ -1772,17 +1770,17 @@ struct sk_buff *ip6_make_skb(struct sock *sk,
 	cork.base.addr = 0;
 	cork.base.opt = NULL;
 	v6_cork.opt = NULL;
-	err = ip6_setup_cork(sk, &cork, &v6_cork, hlimit, tclass, opt, rt, fl6);
+	err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6);
 	if (err)
 		return ERR_PTR(err);
 
-	if (dontfrag < 0)
-		dontfrag = inet6_sk(sk)->dontfrag;
+	if (ipc6->dontfrag < 0)
+		ipc6->dontfrag = inet6_sk(sk)->dontfrag;
 
 	err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork,
 				&current->task_frag, getfrag, from,
 				length + exthdrlen, transhdrlen + exthdrlen,
-				flags, dontfrag, sockc);
+				flags, ipc6, sockc);
 	if (err) {
 		__ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork);
 		return ERR_PTR(err);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 4ff4b29..a9895e1 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -473,7 +473,7 @@ sticky_done:
 		struct msghdr msg;
 		struct flowi6 fl6;
 		struct sockcm_cookie sockc_junk;
-		int junk;
+		struct ipcm6_cookie ipc6;
 
 		memset(&fl6, 0, sizeof(fl6));
 		fl6.flowi6_oif = sk->sk_bound_dev_if;
@@ -503,9 +503,9 @@ sticky_done:
 
 		msg.msg_controllen = optlen;
 		msg.msg_control = (void *)(opt+1);
+		ipc6.opt = opt;
 
-		retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk,
-					     &junk, &junk, &sockc_junk);
+		retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, &ipc6, &sockc_junk);
 		if (retv)
 			goto done;
 update:
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c
index da1cff7..3ee3e44 100644
--- a/net/ipv6/ping.c
+++ b/net/ipv6/ping.c
@@ -58,11 +58,11 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	int iif = 0;
 	struct flowi6 fl6;
 	int err;
-	int hlimit;
 	struct dst_entry *dst;
 	struct rt6_info *rt;
 	struct pingfakehdr pfh;
 	struct sockcm_cookie junk = {0};
+	struct ipcm6_cookie ipc6;
 
 	pr_debug("ping_v6_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num);
 
@@ -139,13 +139,15 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	pfh.wcheck = 0;
 	pfh.family = AF_INET6;
 
-	hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	ipc6.tclass = np->tclass;
+	ipc6.dontfrag = np->dontfrag;
+	ipc6.opt = NULL;
 
 	lock_sock(sk);
 	err = ip6_append_data(sk, ping_getfrag, &pfh, len,
-			      0, hlimit,
-			      np->tclass, NULL, &fl6, rt,
-			      MSG_DONTWAIT, np->dontfrag, &junk);
+			      0, &ipc6, &fl6, rt,
+			      MSG_DONTWAIT, &junk);
 
 	if (err) {
 		ICMP6_INC_STATS(sock_net(sk), rt->rt6i_idev,
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index b07ce21..896350d 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -746,10 +746,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	struct raw6_frag_vec rfv;
 	struct flowi6 fl6;
 	struct sockcm_cookie sockc;
+	struct ipcm6_cookie ipc6;
 	int addr_len = msg->msg_namelen;
-	int hlimit = -1;
-	int tclass = -1;
-	int dontfrag = -1;
 	u16 proto;
 	int err;
 
@@ -770,6 +768,11 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
 	fl6.flowi6_mark = sk->sk_mark;
 
+	ipc6.hlimit = -1;
+	ipc6.tclass = -1;
+	ipc6.dontfrag = -1;
+	ipc6.opt = NULL;
+
 	if (sin6) {
 		if (addr_len < SIN6_LEN_RFC2133)
 			return -EINVAL;
@@ -827,10 +830,9 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		opt = &opt_space;
 		memset(opt, 0, sizeof(struct ipv6_txoptions));
 		opt->tot_len = sizeof(struct ipv6_txoptions);
+		ipc6.opt = opt;
 
-		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-					    &hlimit, &tclass, &dontfrag,
-					    &sockc);
+		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6, &sockc);
 		if (err < 0) {
 			fl6_sock_release(flowlabel);
 			return err;
@@ -846,7 +848,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	if (!opt) {
 		opt = txopt_get(np);
 		opt_to_free = opt;
-		}
+	}
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
@@ -881,14 +883,14 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		err = PTR_ERR(dst);
 		goto out;
 	}
-	if (hlimit < 0)
-		hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	if (ipc6.hlimit < 0)
+		ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
-	if (tclass < 0)
-		tclass = np->tclass;
+	if (ipc6.tclass < 0)
+		ipc6.tclass = np->tclass;
 
-	if (dontfrag < 0)
-		dontfrag = np->dontfrag;
+	if (ipc6.dontfrag < 0)
+		ipc6.dontfrag = np->dontfrag;
 
 	if (msg->msg_flags&MSG_CONFIRM)
 		goto do_confirm;
@@ -897,10 +899,11 @@ back_from_confirm:
 	if (inet->hdrincl)
 		err = rawv6_send_hdrinc(sk, msg, len, &fl6, &dst, msg->msg_flags);
 	else {
+		ipc6.opt = opt;
 		lock_sock(sk);
 		err = ip6_append_data(sk, raw6_getfrag, &rfv,
-			len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info *)dst,
-			msg->msg_flags, dontfrag, &sockc);
+			len, 0, &ipc6, &fl6, (struct rt6_info *)dst,
+			msg->msg_flags, &sockc);
 
 		if (err)
 			ip6_flush_pending_frames(sk);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 1ba5a74..a4dc7ba 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1064,11 +1064,9 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	struct ip6_flowlabel *flowlabel = NULL;
 	struct flowi6 fl6;
 	struct dst_entry *dst;
+	struct ipcm6_cookie ipc6;
 	int addr_len = msg->msg_namelen;
 	int ulen = len;
-	int hlimit = -1;
-	int tclass = -1;
-	int dontfrag = -1;
 	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
 	int err;
 	int connected = 0;
@@ -1076,6 +1074,10 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
 	struct sockcm_cookie sockc;
 
+	ipc6.hlimit = -1;
+	ipc6.tclass = -1;
+	ipc6.dontfrag = -1;
+
 	/* destination address check */
 	if (sin6) {
 		if (addr_len < offsetof(struct sockaddr, sa_data))
@@ -1200,10 +1202,9 @@ do_udp_sendmsg:
 		opt = &opt_space;
 		memset(opt, 0, sizeof(struct ipv6_txoptions));
 		opt->tot_len = sizeof(*opt);
+		ipc6.opt = opt;
 
-		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-					    &hlimit, &tclass, &dontfrag,
-					    &sockc);
+		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6, &sockc);
 		if (err < 0) {
 			fl6_sock_release(flowlabel);
 			return err;
@@ -1224,6 +1225,7 @@ do_udp_sendmsg:
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
+	ipc6.opt = opt;
 
 	fl6.flowi6_proto = sk->sk_protocol;
 	if (!ipv6_addr_any(daddr))
@@ -1253,11 +1255,11 @@ do_udp_sendmsg:
 		goto out;
 	}
 
-	if (hlimit < 0)
-		hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	if (ipc6.hlimit < 0)
+		ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
-	if (tclass < 0)
-		tclass = np->tclass;
+	if (ipc6.tclass < 0)
+		ipc6.tclass = np->tclass;
 
 	if (msg->msg_flags&MSG_CONFIRM)
 		goto do_confirm;
@@ -1268,9 +1270,9 @@ back_from_confirm:
 		struct sk_buff *skb;
 
 		skb = ip6_make_skb(sk, getfrag, msg, ulen,
-				   sizeof(struct udphdr), hlimit, tclass, opt,
+				   sizeof(struct udphdr), &ipc6,
 				   &fl6, (struct rt6_info *)dst,
-				   msg->msg_flags, dontfrag, &sockc);
+				   msg->msg_flags, &sockc);
 		err = PTR_ERR(skb);
 		if (!IS_ERR_OR_NULL(skb))
 			err = udp_v6_send_skb(skb, &fl6);
@@ -1291,14 +1293,12 @@ back_from_confirm:
 	up->pending = AF_INET6;
 
 do_append_data:
-	if (dontfrag < 0)
-		dontfrag = np->dontfrag;
+	if (ipc6.dontfrag < 0)
+		ipc6.dontfrag = np->dontfrag;
 	up->len += ulen;
-	err = ip6_append_data(sk, getfrag, msg, ulen,
-		sizeof(struct udphdr), hlimit, tclass, opt, &fl6,
-		(struct rt6_info *)dst,
-		corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag,
-		&sockc);
+	err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr),
+			      &ipc6, &fl6, (struct rt6_info *)dst,
+			      corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, &sockc);
 	if (err)
 		udp_v6_flush_pending_frames(sk);
 	else if (!corkreq)
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 46e0726..ca215e7 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -495,10 +495,8 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	struct dst_entry *dst = NULL;
 	struct flowi6 fl6;
 	struct sockcm_cookie sockc_unused = {0};
+	struct ipcm6_cookie ipc6;
 	int addr_len = msg->msg_namelen;
-	int hlimit = -1;
-	int tclass = -1;
-	int dontfrag = -1;
 	int transhdrlen = 4; /* zero session-id */
 	int ulen = len + transhdrlen;
 	int err;
@@ -520,6 +518,10 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
 	fl6.flowi6_mark = sk->sk_mark;
 
+	ipc6.hlimit = -1;
+	ipc6.tclass = -1;
+	ipc6.dontfrag = -1;
+
 	if (lsa) {
 		if (addr_len < SIN6_LEN_RFC2133)
 			return -EINVAL;
@@ -564,11 +566,11 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		opt = &opt_space;
 		memset(opt, 0, sizeof(struct ipv6_txoptions));
 		opt->tot_len = sizeof(struct ipv6_txoptions);
+		ipc6.opt = opt;
 
-                err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-                                            &hlimit, &tclass, &dontfrag,
-                                            &sockc_unused);
-                if (err < 0) {
+		err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6,
+					    &sockc_unused);
+		if (err < 0) {
 			fl6_sock_release(flowlabel);
 			return err;
 		}
@@ -588,6 +590,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
+	ipc6.opt = opt;
 
 	fl6.flowi6_proto = sk->sk_protocol;
 	if (!ipv6_addr_any(daddr))
@@ -612,14 +615,14 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 		goto out;
 	}
 
-	if (hlimit < 0)
-		hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
+	if (ipc6.hlimit < 0)
+		ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
 
-	if (tclass < 0)
-		tclass = np->tclass;
+	if (ipc6.tclass < 0)
+		ipc6.tclass = np->tclass;
 
-	if (dontfrag < 0)
-		dontfrag = np->dontfrag;
+	if (ipc6.dontfrag < 0)
+		ipc6.dontfrag = np->dontfrag;
 
 	if (msg->msg_flags & MSG_CONFIRM)
 		goto do_confirm;
@@ -627,9 +630,9 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 back_from_confirm:
 	lock_sock(sk);
 	err = ip6_append_data(sk, ip_generic_getfrag, msg,
-			      ulen, transhdrlen, hlimit, tclass, opt,
+			      ulen, transhdrlen, &ipc6,
 			      &fl6, (struct rt6_info *)dst,
-			      msg->msg_flags, dontfrag, &sockc_unused);
+			      msg->msg_flags, &sockc_unused);
 	if (err)
 		ip6_flush_pending_frames(sk);
 	else if (!(msg->msg_flags & MSG_MORE))
-- 
2.8.0.rc3.226.g39d4020

^ permalink raw reply related

* Re: [PATCHv4] netem: Segment GSO packets on enqueue
From: David Miller @ 2016-05-03  4:34 UTC (permalink / raw)
  To: nhorman; +Cc: netdev, jhs, netem, eric.dumazet, stephen
In-Reply-To: <1462206015-3484-1-git-send-email-nhorman@tuxdriver.com>

From: Neil Horman <nhorman@tuxdriver.com>
Date: Mon,  2 May 2016 12:20:15 -0400

> This was recently reported to me, and reproduced on the latest net kernel,
> when attempting to run netperf from a host that had a netem qdisc attached
> to the egress interface:
 ...
> The problem occurs because netem is not prepared to handle GSO packets (as it
> uses skb_checksum_help in its enqueue path, which cannot manipulate these
> frames).
> 
> The solution I think is to simply segment the skb in a simmilar fashion to the
> way we do in __dev_queue_xmit (via validate_xmit_skb), with some minor changes.
> When we decide to corrupt an skb, if the frame is GSO, we segment it, corrupt
> the first segment, and enqueue the remaining ones.
> 
> tested successfully by myself on the latest net kernel, to which this applies
> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>

Applied and queued up for -stable, thanks Neil.

^ permalink raw reply

* Re: [PATCH net-next] net: relax expensive skb_unclone() in iptunnel_handle_offloads()
From: David Miller @ 2016-05-03  4:23 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev
In-Reply-To: <1462036769.5535.180.camel@edumazet-glaptop3.roam.corp.google.com>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Sat, 30 Apr 2016 10:19:29 -0700

> From: Eric Dumazet <edumazet@google.com>
> 
> Locally generated TCP GSO packets having to go through a GRE/SIT/IPIP
> tunnel have to go through an expensive skb_unclone()
> 
> Reallocating skb->head is a lot of work.
> 
> Test should really check if a 'real clone' of the packet was done.
> 
> TCP does not care if the original gso_type is changed while the packet
> travels in the stack.
> 
> This adds skb_header_unclone() which is a variant of skb_clone()
> using skb_header_cloned() check instead of skb_cloned().
> 
> This variant can probably be used from other points.
> 
> Signed-off-by: Eric Dumazet <edumazet@google.com>

Nice observation, applied, thanks Eric.

^ permalink raw reply

* Re: pull request [net]: batman-adv 20160430
From: David Miller @ 2016-05-03  4:18 UTC (permalink / raw)
  To: a
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r
In-Reply-To: <1462035963-28970-1-git-send-email-a-2CpIooy/SPIKlTDg6p0iyA@public.gmane.org>

From: Antonio Quartulli <a@unstable.cc>
Date: Sun,  1 May 2016 01:05:59 +0800

> this is another pull request intended for net.
> 
> I know that I sent another batch a few days ago, but after having gone
> through my queue I thought that merging these last 4 patches would still
> be worth it (there won't be any other pull request for linux-4.6 :)).
> 
> The description of the changes follows below.

Pulled, thanks Antonio.

^ permalink raw reply

* Re: [PATCH net] vlan: Propagate MAC address changes properly
From: David Miller @ 2016-05-03  4:16 UTC (permalink / raw)
  To: mmanning; +Cc: netdev
In-Reply-To: <572489C5.3020502@brocade.com>

From: Mike Manning <mmanning@brocade.com>
Date: Sat, 30 Apr 2016 11:32:37 +0100

> The MAC address of the physical interface is only copied to the VLAN
> when it is first created, resulting in an inconsistency after MAC
> address changes of only newly created VLANs having an up-to-date MAC.
> 
> Continuing to inherit the MAC address unless explicitly changed for
> the VLAN allows IPv6 EUI64 addresses for the VLAN to reflect the change
> and thus for DAD to behave as expected for the given MAC.
> 
> Signed-off-by: Mike Manning <mmanning@brocade.com>

What is this code really trying to achieve?

Is it "Propagate real device MAC changes to undelying vlan device,
but not if the user set the vlan MAC explicitly."?

If so, implement that instead of all of these confusing tests.

If the vlan device's set_mac_address operation is ever called,
set a boolean value in the vlan device private to true and test
it here.

^ permalink raw reply

* linux-next: manual merge of the net-next tree with Linus' tree
From: Stephen Rothwell @ 2016-05-03  3:15 UTC (permalink / raw)
  To: David Miller, netdev; +Cc: linux-next, linux-kernel, Jiri Benc, Tom Herbert

Hi all,

Today's linux-next merge of the net-next tree got a conflict in:

  net/ipv4/ip_gre.c

between commits:

  2090714e1d6e ("gre: build header correctly for collect metadata tunnels")
  b7f8fe251e46 ("gre: do not pull header in ICMP error processing")

from Linus' tree and commit:

  95f5c64c3c13 ("gre: Move utility functions to common headers")
  182a352d2d5e ("gre: Create common functions for transmit")

from the net-next tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

-- 
Cheers,
Stephen Rothwell

diff --cc net/ipv4/ip_gre.c
index 205a2b8a5a84,2480d79b0e37..000000000000
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@@ -341,8 -221,9 +221,9 @@@ static void gre_err(struct sk_buff *skb
  	const int code = icmp_hdr(skb)->code;
  	struct tnl_ptk_info tpi;
  	bool csum_err = false;
+ 	int hdr_len;
  
- 	if (parse_gre_header(skb, &tpi, &csum_err) < 0) {
 -	if (gre_parse_header(skb, &tpi, &csum_err, &hdr_len)) {
++	if (gre_parse_header(skb, &tpi, &csum_err, &hdr_len) < 0) {
  		if (!csum_err)		/* ignore csum errors. */
  			return;
  	}
@@@ -574,15 -414,12 +415,12 @@@ static void gre_fb_xmit(struct sk_buff 
  	}
  
  	/* Push Tunnel header. */
- 	skb = gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM));
- 	if (IS_ERR(skb)) {
- 		skb = NULL;
+ 	if (gre_handle_offloads(skb, !!(tun_info->key.tun_flags & TUNNEL_CSUM)))
  		goto err_free_rt;
- 	}
  
  	flags = tun_info->key.tun_flags & (TUNNEL_CSUM | TUNNEL_KEY);
- 	build_header(skb, tunnel_hlen, flags, proto,
- 		     tunnel_id_to_key(tun_info->key.tun_id), 0);
 -	gre_build_header(skb, tunnel_hlen, flags, htons(ETH_P_TEB),
++	gre_build_header(skb, tunnel_hlen, flags, proto,
+ 			 tunnel_id_to_key(tun_info->key.tun_id), 0);
  
  	df = key->tun_flags & TUNNEL_DONT_FRAGMENT ?  htons(IP_DF) : 0;
  

^ permalink raw reply

* Re: [PATCH] vhost_net: stop polling socket during rx processing
From: Jason Wang @ 2016-05-03  2:52 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: netdev, linux-kernel, kvm, virtualization
In-Reply-To: <5721AB7B.8070806@redhat.com>



On 04/28/2016 02:19 PM, Jason Wang wrote:
> On 04/27/2016 07:28 PM, Michael S. Tsirkin wrote:
>> > On Tue, Apr 26, 2016 at 03:35:53AM -0400, Jason Wang wrote:
>>> >> We don't stop polling socket during rx processing, this will lead
>>> >> unnecessary wakeups from under layer net devices (E.g
>>> >> sock_def_readable() form tun). Rx will be slowed down in this
>>> >> way. This patch avoids this by stop polling socket during rx
>>> >> processing. A small drawback is that this introduces some overheads in
>>> >> light load case because of the extra start/stop polling, but single
>>> >> netperf TCP_RR does not notice any change. In a super heavy load case,
>>> >> e.g using pktgen to inject packet to guest, we get about ~17%
>>> >> improvement on pps:
>>> >>
>>> >> before: ~1370000 pkt/s
>>> >> after:  ~1500000 pkt/s
>>> >>
>>> >> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> > Acked-by: Michael S. Tsirkin <mst@redhat.com>
>> >
>> > There is one other possible enhancement: we actually have the wait queue
>> > lock taken in _wake_up, but we give it up only to take it again in the
>> > handler.
>> >
>> > It would be nicer to just remove the entry when we wake
>> > the vhost thread. Re-add it if required.
>> > I think that something like the below would give you the necessary API.
>> > Pls feel free to use it if you are going to implement a patch on top
>> > doing this - that's not a reason not to include this simple patch
>> > though.
> Thanks, this looks useful, will give it a try.

Want to try, but looks like this will result a strange API:

- poll were removed automatically during wakeup, handler does not need
to care about this
- but handler still need to re-add the poll explicitly in the code

?

^ permalink raw reply

* Re: [PATCH next] netdevice: shrink size of struct netdev_queue
From: David Miller @ 2016-05-03  2:51 UTC (permalink / raw)
  To: fw; +Cc: netdev
In-Reply-To: <1462238949-3271-1-git-send-email-fw@strlen.de>

From: Florian Westphal <fw@strlen.de>
Date: Tue,  3 May 2016 03:29:09 +0200

> - trans_timeout is incremented when tx queue timed out (tx watchdog).
> - tx_maxrate is set via sysfs
> 
> Moving tx_maxrate to read-mostly part shrinks the struct by 64 bytes.
> While at it, also move trans_timeout (it is out-of-place in the
> 'write-mostly' part).
> 
> Signed-off-by: Florian Westphal <fw@strlen.de>

Applied, thanks Florian.

^ permalink raw reply

* Re: [PATCH net-next] ipv6: add new struct ipcm6_cookie
From: David Miller @ 2016-05-03  2:46 UTC (permalink / raw)
  To: weiwan; +Cc: netdev, edumazet
In-Reply-To: <20160502.223945.1841569316439730448.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Date: Mon, 02 May 2016 22:39:45 -0400 (EDT)

> From: Wei Wang <weiwan@google.com>
> Date: Fri, 29 Apr 2016 17:31:12 -0700
> 
>> From: Wei Wang <weiwan@google.com>
>> 
>> In the sendmsg function of UDP, raw, ICMP and l2tp sockets, we use local
>> variables like hlimits, tclass, opt and dontfrag and pass them to corresponding
>> functions like ip6_make_skb, ip6_append_data and xxx_push_pending_frames.
>> This is not a good practice and makes it hard to add new parameters.
>> This fix introduces a new struct ipcm6_cookie similar to ipcm_cookie in
>> ipv4 and include the above mentioned variables. And we only pass the
>> pointer to this structure to corresponding functions. This makes it easier
>> to add new parameters in the future and makes the function cleaner.
>> 
>> Signed-off-by: Wei Wang <weiwan@google.com>
> 
> Looks good, applied, thank you.

Actually I had to revert, this break the build.

net/l2tp/l2tp_ip6.c: In function ‘l2tp_ip6_sendmsg’:
net/l2tp/l2tp_ip6.c:634:10: error: invalid operands to binary & (have ‘struct ipcm6_cookie *’ and ‘struct flowi6’)
          &fl6, (struct rt6_info *)dst,
          ^
net/l2tp/l2tp_ip6.c:634:16: warning: passing argument 7 of ‘ip6_append_data’ from incompatible pointer type
          &fl6, (struct rt6_info *)dst,
                ^

and so on and so forth...

^ permalink raw reply

* Re: [PATCH] ip: add udp_csum, udp6_csum_tx, udp6_csum_rx control flags to ip l2tp add tunnel
From: Wang Shanker @ 2016-05-03  2:40 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: James Chapman, netdev
In-Reply-To: <20160502151910.3a1f6f3d@xeon-e3>

[-- Attachment #1: Type: text/plain, Size: 2198 bytes --]

Thanks a lot.

I feel it excited to contribute to the development of kernel. I’ll do 
better next time.

> 在 2016年5月3日,06:19,Stephen Hemminger <stephen@networkplumber.org> 写道:
> 
> On Thu, 28 Apr 2016 15:50:47 +0100
> James Chapman <jchapman@katalix.com> wrote:
> 
>> Yes, that looks like the problem.
>> 
>> The comments in l2tp.h which indicate that the csum attributes are u8
>> values are wrong. Code in net/l2tp/l2tp_netlink.c accesses these
>> attributes using nla_get_flag().
>> 
>> Please submit a patch to fix l2tp_tunnel_sock_create(). Include good
>> change notes and your signed-off-by tag so that it gets reviewed. See
>> Documentation/SubmittingPatches if you haven't submitted a kernel
>> patch here before.
> 
> Thank you for fixing this. James is is correct.
> Please format the patch according to the submission guidelines.
> For example, checkpatch complains about current patch.
> 
> ERROR: code indent should use tabs where possible
> #156: FILE: net/l2tp/l2tp_core.c:1379:
> +                         ! cfg->udp6_zero_tx_checksums;$
> 
> WARNING: please, no spaces at the start of a line
> #156: FILE: net/l2tp/l2tp_core.c:1379:
> +                         ! cfg->udp6_zero_tx_checksums;$
> 
> ERROR: space prohibited after that '!' (ctx:ExW)
> #156: FILE: net/l2tp/l2tp_core.c:1379:
> +                         ! cfg->udp6_zero_tx_checksums;
>                          ^
> 
> ERROR: code indent should use tabs where possible
> #159: FILE: net/l2tp/l2tp_core.c:1381:
> +                         ! cfg->udp6_zero_rx_checksums;$
> 
> WARNING: please, no spaces at the start of a line
> #159: FILE: net/l2tp/l2tp_core.c:1381:
> +                         ! cfg->udp6_zero_rx_checksums;$
> 
> ERROR: space prohibited after that '!' (ctx:ExW)
> #159: FILE: net/l2tp/l2tp_core.c:1381:
> +                         ! cfg->udp6_zero_rx_checksums;
>                          ^
> 
> ERROR: Missing Signed-off-by: line(s)
> 
> 
> I am sorry that maintainers may seem like picky teachers in school
> always putting redline around spelling errors, but this is how we work to teach
> others how to follow the process.
> 


[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 4130 bytes --]

^ permalink raw reply

* Re: [PATCH net-next] ipv6: add new struct ipcm6_cookie
From: David Miller @ 2016-05-03  2:39 UTC (permalink / raw)
  To: weiwan; +Cc: netdev, edumazet
In-Reply-To: <1461976272-10738-1-git-send-email-tracywwnj@gmail.com>

From: Wei Wang <weiwan@google.com>
Date: Fri, 29 Apr 2016 17:31:12 -0700

> From: Wei Wang <weiwan@google.com>
> 
> In the sendmsg function of UDP, raw, ICMP and l2tp sockets, we use local
> variables like hlimits, tclass, opt and dontfrag and pass them to corresponding
> functions like ip6_make_skb, ip6_append_data and xxx_push_pending_frames.
> This is not a good practice and makes it hard to add new parameters.
> This fix introduces a new struct ipcm6_cookie similar to ipcm_cookie in
> ipv4 and include the above mentioned variables. And we only pass the
> pointer to this structure to corresponding functions. This makes it easier
> to add new parameters in the future and makes the function cleaner.
> 
> Signed-off-by: Wei Wang <weiwan@google.com>

Looks good, applied, thank you.

^ permalink raw reply

* Re: [PATCH net-next v3 0/4] bridge: per-vlan stats
From: David Miller @ 2016-05-03  2:27 UTC (permalink / raw)
  To: nikolay; +Cc: netdev, roopa, stephen
In-Reply-To: <1462004729-12185-1-git-send-email-nikolay@cumulusnetworks.com>

From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Date: Sat, 30 Apr 2016 10:25:25 +0200

> This set adds support for bridge per-vlan statistics.

This looks a lot better, series applied, thanks!

^ permalink raw reply

* Re: [PATCH next-next 0/7] net: Cleanup IPv6 ip tunnels
From: Alexander Duyck @ 2016-05-03  2:03 UTC (permalink / raw)
  To: Tom Herbert; +Cc: David Miller, Netdev, Kernel Team
In-Reply-To: <1461975141-954269-1-git-send-email-tom@herbertland.com>

On Fri, Apr 29, 2016 at 5:12 PM, Tom Herbert <tom@herbertland.com> wrote:
> The IPv6 tunnel code is very different from IPv4 code. There is a lot
> of redundancy with the IPv4 code, particularly in the GRE tunneling.
>
> This patch set cleans up the tunnel code to make the IPv6 code look
> more like the IPv4 code and use common functions between the two
> stacks where possible.
>
> This work should make it easier to maintain and extend the IPv6 ip
> tunnels.
>
> Items in this patch set:
>   - Cleanup IPv6 tunnel receive path (ip6_tnl_rcv). Includes using
>     gro_cells and exporting ip6_tnl_rcv so the ip6_gre can call it
>   - Move GRE functions to common header file (tx functions) or
>     gre_demux.c (rx functions like gre_parse_header)
>   - Call common GRE functions from IPv6 GRE
>   - Create ip6_tnl_xmit (to be like ip_tunnel_xmit)
>
> Tested:
>   Ran super_netperf tests for TCP_RR and TCP_STREAM for:
>     - IPv4 over gre, gretap, gre6, gre6tap
>     - IPv6 over gre, gretap, gre6, gre6tap
>     - ipip
>     - ip6ip6
>     - ipip/gue
>     - IPv6 over gre/gue
>     - IPv4 over gre/gue
>
> Tom Herbert (7):
>   ipv6: Cleanup IPv6 tunnel receive path
>   gre: Move utility functions to common headers
>   gre6: Cleanup GREv6 receive path, call common GRE functions
>   ipv6: Create ip6_tnl_xmit
>   gre: Create common functions for transmit
>   ipv6: Generic tunnel cleanup
>   gre6: Cleanup GREv6 transmit path, call common GRE functions
>
>  include/net/gre.h        | 104 +++++++++++++
>  include/net/ip6_tunnel.h |  11 +-
>  net/ipv4/gre_demux.c     |  64 ++++++++
>  net/ipv4/ip_gre.c        | 199 +++---------------------
>  net/ipv6/ip6_gre.c       | 392 +++++++++--------------------------------------
>  net/ipv6/ip6_tunnel.c    | 266 +++++++++++++++++++++-----------
>  6 files changed, 452 insertions(+), 584 deletions(-)
>
> --
> 2.8.0.rc2
>

I was wondering if you have more work going on in this area or not?  I
ask because I was just going through and auditing the calls to
skb_reset_inner_headers and I think the only spot left that is calling
it without verifying that either GSO or CHECKSUM_PARTIAL is set is in
ip6_tnl_xmit.  If we can get that moved over to using
iptunnel_handle_offloads like the other functions then we should be
guaranteed that skb->encapsulation is only ever set if an offload is
requested, and that in turn guarantees that csum_start and
inner_transport_offset will always be the same value.

Thanks.

- Alex

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox