01 Feb, 2018

1 commit

  • Currently, rocker user may experience following null pointer
    derefence bug:

    [ 3.062141] BUG: unable to handle kernel NULL pointer dereference at 00000000000000d0
    [ 3.065163] IP: rocker_router_fib_event_work+0x36/0x110 [rocker]

    The problem is uninitialized rocker->wops pointer that is initialized
    only with the first initialized port. So move the port initialization
    before registering the fib events.

    Fixes: 936bd486564a ("rocker: use FIB notifications instead of switchdev calls")
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Jiri Pirko
     

28 Jan, 2018

1 commit


22 Nov, 2017

1 commit

  • This converts all remaining cases of the old setup_timer() API into using
    timer_setup(), where the callback argument is the structure already
    holding the struct timer_list. These should have no behavioral changes,
    since they just change which pointer is passed into the callback with
    the same available pointers after conversion. It handles the following
    examples, in addition to some other variations.

    Casting from unsigned long:

    void my_callback(unsigned long data)
    {
    struct something *ptr = (struct something *)data;
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, ptr);

    and forced object casts:

    void my_callback(struct something *ptr)
    {
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);

    become:

    void my_callback(struct timer_list *t)
    {
    struct something *ptr = from_timer(ptr, t, my_timer);
    ...
    }
    ...
    timer_setup(&ptr->my_timer, my_callback, 0);

    Direct function assignments:

    void my_callback(unsigned long data)
    {
    struct something *ptr = (struct something *)data;
    ...
    }
    ...
    ptr->my_timer.function = my_callback;

    have a temporary cast added, along with converting the args:

    void my_callback(struct timer_list *t)
    {
    struct something *ptr = from_timer(ptr, t, my_timer);
    ...
    }
    ...
    ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;

    And finally, callbacks without a data assignment:

    void my_callback(unsigned long data)
    {
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, 0);

    have their argument renamed to verify they're unused during conversion:

    void my_callback(struct timer_list *unused)
    {
    ...
    }
    ...
    timer_setup(&ptr->my_timer, my_callback, 0);

    The conversion is done with the following Coccinelle script:

    spatch --very-quiet --all-includes --include-headers \
    -I ./arch/x86/include -I ./arch/x86/include/generated \
    -I ./include -I ./arch/x86/include/uapi \
    -I ./arch/x86/include/generated/uapi -I ./include/uapi \
    -I ./include/generated/uapi --include ./include/linux/kconfig.h \
    --dir . \
    --cocci-file ~/src/data/timer_setup.cocci

    @fix_address_of@
    expression e;
    @@

    setup_timer(
    -&(e)
    +&e
    , ...)

    // Update any raw setup_timer() usages that have a NULL callback, but
    // would otherwise match change_timer_function_usage, since the latter
    // will update all function assignments done in the face of a NULL
    // function initialization in setup_timer().
    @change_timer_function_usage_NULL@
    expression _E;
    identifier _timer;
    type _cast_data;
    @@

    (
    -setup_timer(&_E->_timer, NULL, _E);
    +timer_setup(&_E->_timer, NULL, 0);
    |
    -setup_timer(&_E->_timer, NULL, (_cast_data)_E);
    +timer_setup(&_E->_timer, NULL, 0);
    |
    -setup_timer(&_E._timer, NULL, &_E);
    +timer_setup(&_E._timer, NULL, 0);
    |
    -setup_timer(&_E._timer, NULL, (_cast_data)&_E);
    +timer_setup(&_E._timer, NULL, 0);
    )

    @change_timer_function_usage@
    expression _E;
    identifier _timer;
    struct timer_list _stl;
    identifier _callback;
    type _cast_func, _cast_data;
    @@

    (
    -setup_timer(&_E->_timer, _callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, &_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, &_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    _E->_timer@_stl.function = _callback;
    |
    _E->_timer@_stl.function = &_callback;
    |
    _E->_timer@_stl.function = (_cast_func)_callback;
    |
    _E->_timer@_stl.function = (_cast_func)&_callback;
    |
    _E._timer@_stl.function = _callback;
    |
    _E._timer@_stl.function = &_callback;
    |
    _E._timer@_stl.function = (_cast_func)_callback;
    |
    _E._timer@_stl.function = (_cast_func)&_callback;
    )

    // callback(unsigned long arg)
    @change_callback_handle_cast
    depends on change_timer_function_usage@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _origtype;
    identifier _origarg;
    type _handletype;
    identifier _handle;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *t
    )
    {
    (
    ... when != _origarg
    _handletype *_handle =
    -(_handletype *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle =
    -(void *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle;
    ... when != _handle
    _handle =
    -(_handletype *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle;
    ... when != _handle
    _handle =
    -(void *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    )
    }

    // callback(unsigned long arg) without existing variable
    @change_callback_handle_cast_no_arg
    depends on change_timer_function_usage &&
    !change_callback_handle_cast@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _origtype;
    identifier _origarg;
    type _handletype;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *t
    )
    {
    + _handletype *_origarg = from_timer(_origarg, t, _timer);
    +
    ... when != _origarg
    - (_handletype *)_origarg
    + _origarg
    ... when != _origarg
    }

    // Avoid already converted callbacks.
    @match_callback_converted
    depends on change_timer_function_usage &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg@
    identifier change_timer_function_usage._callback;
    identifier t;
    @@

    void _callback(struct timer_list *t)
    { ... }

    // callback(struct something *handle)
    @change_callback_handle_arg
    depends on change_timer_function_usage &&
    !match_callback_converted &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _handletype;
    identifier _handle;
    @@

    void _callback(
    -_handletype *_handle
    +struct timer_list *t
    )
    {
    + _handletype *_handle = from_timer(_handle, t, _timer);
    ...
    }

    // If change_callback_handle_arg ran on an empty function, remove
    // the added handler.
    @unchange_callback_handle_arg
    depends on change_timer_function_usage &&
    change_callback_handle_arg@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _handletype;
    identifier _handle;
    identifier t;
    @@

    void _callback(struct timer_list *t)
    {
    - _handletype *_handle = from_timer(_handle, t, _timer);
    }

    // We only want to refactor the setup_timer() data argument if we've found
    // the matching callback. This undoes changes in change_timer_function_usage.
    @unchange_timer_function_usage
    depends on change_timer_function_usage &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg &&
    !change_callback_handle_arg@
    expression change_timer_function_usage._E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type change_timer_function_usage._cast_data;
    @@

    (
    -timer_setup(&_E->_timer, _callback, 0);
    +setup_timer(&_E->_timer, _callback, (_cast_data)_E);
    |
    -timer_setup(&_E._timer, _callback, 0);
    +setup_timer(&_E._timer, _callback, (_cast_data)&_E);
    )

    // If we fixed a callback from a .function assignment, fix the
    // assignment cast now.
    @change_timer_function_assignment
    depends on change_timer_function_usage &&
    (change_callback_handle_cast ||
    change_callback_handle_cast_no_arg ||
    change_callback_handle_arg)@
    expression change_timer_function_usage._E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type _cast_func;
    typedef TIMER_FUNC_TYPE;
    @@

    (
    _E->_timer.function =
    -_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -(_cast_func)_callback;
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -(_cast_func)&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -&_callback;
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -(_cast_func)_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -(_cast_func)&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    )

    // Sometimes timer functions are called directly. Replace matched args.
    @change_timer_function_calls
    depends on change_timer_function_usage &&
    (change_callback_handle_cast ||
    change_callback_handle_cast_no_arg ||
    change_callback_handle_arg)@
    expression _E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type _cast_data;
    @@

    _callback(
    (
    -(_cast_data)_E
    +&_E->_timer
    |
    -(_cast_data)&_E
    +&_E._timer
    |
    -_E
    +&_E->_timer
    )
    )

    // If a timer has been configured without a data argument, it can be
    // converted without regard to the callback argument, since it is unused.
    @match_timer_function_unused_data@
    expression _E;
    identifier _timer;
    identifier _callback;
    @@

    (
    -setup_timer(&_E->_timer, _callback, 0);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, 0L);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, 0UL);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0L);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0UL);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0L);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0UL);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0);
    +timer_setup(_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0L);
    +timer_setup(_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0UL);
    +timer_setup(_timer, _callback, 0);
    )

    @change_callback_unused_data
    depends on match_timer_function_unused_data@
    identifier match_timer_function_unused_data._callback;
    type _origtype;
    identifier _origarg;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *unused
    )
    {
    ... when != _origarg
    }

    Signed-off-by: Kees Cook

    Kees Cook
     

26 Sep, 2017

1 commit

  • Inlining these functions creates lots of stack variables that each take
    64 bytes when KASAN is enabled, leading to this warning about potential
    stack overflow:

    drivers/net/ethernet/rocker/rocker_ofdpa.c: In function 'ofdpa_cmd_flow_tbl_add':
    drivers/net/ethernet/rocker/rocker_ofdpa.c:621:1: error: the frame size of 2752 bytes is larger than 1536 bytes [-Werror=frame-larger-than=]

    gcc-8 can now consolidate the stack slots itself, but on older versions
    we get the same behavior by using a temporary variable that holds a
    copy of the inline function argument.

    Cc: stable@vger.kernel.org
    Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81715
    Signed-off-by: Arnd Bergmann
    Signed-off-by: David S. Miller

    Arnd Bergmann
     

06 Sep, 2017

1 commit

  • The function calls to kcalloc use wrong parameter order and incorrect flags
    values. GFP_KERNEL is used instead of flags now and the order is corrected.

    The change was done using the following coccinelle script:

    @@
    expression E1,E2;
    type T;
    @@

    -kcalloc(E1, E2, sizeof(T))
    +kcalloc(E2, sizeof(T), GFP_KERNEL)

    Signed-off-by: Zahari Doychev
    Signed-off-by: David S. Miller

    Zahari Doychev
     

04 Aug, 2017

2 commits

  • As in previous patch, ignore IPv6 notifications since the driver doesn't
    support these.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     
  • The FIB notification chain is currently soley used by IPv4 code.
    However, we're going to introduce IPv6 FIB offload support, which
    requires these notification as well.

    As explained in commit c3852ef7f2f8 ("ipv4: fib: Replay events when
    registering FIB notifier"), upon registration to the chain, the callee
    receives a full dump of the FIB tables and rules by traversing all the
    net namespaces. The integrity of the dump is ensured by a per-namespace
    sequence counter that is incremented whenever a change to the tables or
    rules occurs.

    In order to allow more address families to use the chain, each family is
    expected to register its fib_notifier_ops in its pernet init. These
    operations allow the common code to read the family's sequence counter
    as well as dump its tables and rules in the given net namespace.

    Additionally, a 'family' parameter is added to sent notifications, so
    that listeners could distinguish between the different families.

    Implement the common code that allows listeners to register to the chain
    and for address families to register their fib_notifier_ops. Subsequent
    patches will implement these operations in IPv6.

    In the future, ipmr and ip6mr will be extended to provide these
    notifications as well.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     

03 Aug, 2017

1 commit

  • We want to stop using the FIB info's flags to provide the offlaod
    indication and instead do that on a per-nexthop basis.

    Convert rocker to do just that. It only supports one nexthop per-route,
    so conversion is simple.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     

01 Jul, 2017

1 commit


30 Jun, 2017

1 commit

  • My static checker complains that ofdpa_neigh_del() can sometimes free
    "found". It just makes sense to use it first before deleting it.

    Fixes: ecf244f753e0 ("rocker: fix maybe-uninitialized warning")
    Signed-off-by: Dan Carpenter
    Signed-off-by: David S. Miller

    Dan Carpenter
     

09 Jun, 2017

7 commits


06 Apr, 2017

1 commit


29 Mar, 2017

1 commit

  • gcc-7 reports a warning that earlier versions did not have:

    drivers/net/ethernet/rocker/rocker_ofdpa.c: In function 'ofdpa_port_stp_update':
    arch/x86/include/asm/string_32.h:79:22: error: '*((void *)&prev_ctrls+4)' may be used uninitialized in this function [-Werror=maybe-uninitialized]
    *((short *)to + 2) = *((short *)from + 2);
    ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
    drivers/net/ethernet/rocker/rocker_ofdpa.c:2218:7: note: '*((void *)&prev_ctrls+4)' was declared here

    This is clearly a variation of the warning about 'prev_state' that
    was shut up using uninitialized_var().

    We can slightly simplify the code and get rid of the warning by unconditionally
    saving the prev_state and prev_ctrls variables. The inlined memcpy is not
    particularly expensive here, as it just has to read five bytes from one or
    two cache lines.

    Signed-off-by: Arnd Bergmann
    Signed-off-by: David S. Miller

    Arnd Bergmann
     

17 Mar, 2017

1 commit

  • In commit c3852ef7f2f8 ("ipv4: fib: Replay events when registering FIB
    notifier") we dumped the FIB tables and replayed the events to the
    passed notification block.

    However, we merely sent a RULE_ADD notification in case custom rules
    were in use. As explained in previous patches, this approach won't work
    anymore. Instead, we should notify the caller about all the FIB rules
    and let it act accordingly.

    Upon registration to the FIB notification chain, replay a RULE_ADD
    notification for each programmed FIB rule, custom or not. The integrity
    of the dump is ensured by the mechanism introduced in the above
    mentioned commit.

    Prevent regressions by making sure current listeners correctly sanitize
    the notified rules.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Acked-by: David Ahern
    Signed-off-by: David S. Miller

    Ido Schimmel
     

07 Mar, 2017

1 commit


31 Jan, 2017

1 commit

  • napi_complete_done() allows to opt-in for gro_flush_timeout,
    added back in linux-3.19, commit 3b47d30396ba
    ("net: gro: add a per device gro flush timer")

    This allows for more efficient GRO aggregation without
    sacrifying latencies.

    Signed-off-by: Eric Dumazet
    Signed-off-by: David S. Miller

    Eric Dumazet
     

04 Dec, 2016

4 commits

  • Commit b90eb7549499 ("fib: introduce FIB notification infrastructure")
    introduced a new notification chain to notify listeners (f.e., switchdev
    drivers) about addition and deletion of routes.

    However, upon registration to the chain the FIB tables can already be
    populated, which means potential listeners will have an incomplete view
    of the tables.

    Solve that by dumping the FIB tables and replaying the events to the
    passed notification block. The dump itself is done using RCU in order
    not to starve consumers that need RTNL to make progress.

    The integrity of the dump is ensured by reading the FIB change sequence
    counter before and after the dump under RTNL. This allows us to avoid
    the problematic situation in which the dumping process sends a ENTRY_ADD
    notification following ENTRY_DEL generated by another process holding
    RTNL.

    Callers of the registration function may pass a callback that is
    executed in case the dump was inconsistent with current FIB tables.

    The number of retries until a consistent dump is achieved is set to a
    fixed number to prevent callers from looping for long periods of time.
    In case current limit proves to be problematic in the future, it can be
    easily converted to be configurable using a sysctl.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     
  • We can miss FIB notifications sent between the time the ports were
    created and the FIB notification block registered.

    Instead of receiving these notifications only when they are replayed for
    the FIB notification block during registration, just register the
    notification block before the ports are created.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     
  • Convert rocker to offload FIBs in deferred work in a similar fashion to
    mlxsw, which was converted in the previous commits.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     
  • As explained in the previous commits, we need to process FIB entries
    addition / deletion events in FIFO order or otherwise we can have a
    mismatch between the kernel's FIB table and the device's.

    Create an ordered workqueue for rocker to which these work items will be
    submitted to.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     

31 Oct, 2016

1 commit


30 Oct, 2016

1 commit


27 Oct, 2016

1 commit


19 Oct, 2016

1 commit

  • In some rare configurations, we get a warning about the 'index' variable
    being used without an initialization:

    drivers/net/ethernet/rocker/rocker_ofdpa.c: In function ‘ofdpa_port_fib_ipv4.isra.16.constprop’:
    drivers/net/ethernet/rocker/rocker_ofdpa.c:2425:92: warning: ‘index’ may be used uninitialized in this function [-Wmaybe-uninitialized]

    This is a false positive, the logic is just a bit too complex for gcc
    to follow here. Moving the intialization of 'index' a little further
    down makes it clear to gcc that the function always returns an error
    if it is not initialized.

    Signed-off-by: Arnd Bergmann
    Signed-off-by: David S. Miller

    Arnd Bergmann
     

18 Oct, 2016

2 commits

  • Convert rocker to the new dev walk API. This is just a code conversion;
    no functional change is intended.

    v2
    - removed typecast of data

    Signed-off-by: David Ahern
    Signed-off-by: David S. Miller

    David Ahern
     
  • et131x: min_mtu 64, max_mtu 9216

    altera_tse: min_mtu 64, max_mtu 1500

    amd8111e: min_mtu 60, max_mtu 9000

    bnad: min_mtu 46, max_mtu 9000

    macb: min_mtu 68, max_mtu 1500 or 10240 depending on hardware capability

    xgmac: min_mtu 46, max_mtu 9000

    cxgb2: min_mtu 68, max_mtu 9582 (pm3393) or 9600 (vsc7326)

    enic: min_mtu 68, max_mtu 9000

    gianfar: min_mtu 50, max_mu 9586

    hns_enet: min_mtu 68, max_mtu 9578 (v1) or 9706 (v2)

    ksz884x: min_mtu 60, max_mtu 1894

    myri10ge: min_mtu 68, max_mtu 9000

    natsemi: min_mtu 64, max_mtu 2024

    nfp: min_mtu 68, max_mtu hardware-specific

    forcedeth: min_mtu 64, max_mtu 1500 or 9100, depending on hardware

    pch_gbe: min_mtu 46, max_mtu 10300

    pasemi_mac: min_mtu 64, max_mtu 9000

    qcaspi: min_mtu 46, max_mtu 1500
    - remove qcaspi_netdev_change_mtu as it is now redundant

    rocker: min_mtu 68, max_mtu 9000

    sxgbe: min_mtu 68, max_mtu 9000

    stmmac: min_mtu 46, max_mtu depends on hardware

    tehuti: min_mtu 60, max_mtu 16384
    - driver had no max mtu checking, but product docs say 16k jumbo packets
    are supported by the hardware

    netcp: min_mtu 68, max_mtu 9486
    - remove netcp_ndo_change_mtu as it is now redundant

    via-velocity: min_mtu 64, max_mtu 9000

    octeon: min_mtu 46, max_mtu 65370

    CC: netdev@vger.kernel.org
    CC: Mark Einon
    CC: Vince Bridgers
    CC: Rasesh Mody
    CC: Nicolas Ferre
    CC: Santosh Raspatur
    CC: Hariprasad S
    CC: Christian Benvenuti
    CC: Sujith Sankar
    CC: Govindarajulu Varadarajan
    CC: Neel Patel
    CC: Claudiu Manoil
    CC: Yisen Zhuang
    CC: Salil Mehta
    CC: Hyong-Youb Kim
    CC: Jakub Kicinski
    CC: Olof Johansson
    CC: Jiri Pirko
    CC: Byungho An
    CC: Girish K S
    CC: Vipul Pandya
    CC: Giuseppe Cavallaro
    CC: Alexandre Torgue
    CC: Andy Gospodarek
    CC: Wingman Kwok
    CC: Murali Karicheri
    CC: Francois Romieu
    Signed-off-by: Jarod Wilson
    Signed-off-by: David S. Miller

    Jarod Wilson
     

28 Sep, 2016

1 commit


27 Aug, 2016

1 commit

  • switchdev_port_fwd_mark_set() is used to set the 'offload_fwd_mark' of
    port netdevs so that packets being flooded by the device won't be
    flooded twice.

    It works by assigning a unique identifier (the ifindex of the first
    bridge port) to bridge ports sharing the same parent ID. This prevents
    packets from being flooded twice by the same switch, but will flood
    packets through bridge ports belonging to a different switch.

    This method is problematic when stacked devices are taken into account,
    such as VLANs. In such cases, a physical port netdev can have upper
    devices being members in two different bridges, thus requiring two
    different 'offload_fwd_mark's to be configured on the port netdev, which
    is impossible.

    The main problem is that packet and netdev marking is performed at the
    physical netdev level, whereas flooding occurs between bridge ports,
    which are not necessarily port netdevs.

    Instead, packet and netdev marking should really be done in the bridge
    driver with the switch driver only telling it which packets it already
    forwarded. The bridge driver will mark such packets using the mark
    assigned to the ingress bridge port and will prevent the packet from
    being forwarded through any bridge port sharing the same mark (i.e.
    having the same parent ID).

    Remove the current switchdev 'offload_fwd_mark' implementation and
    instead implement the proposed method. In addition, make rocker - the
    sole user of the mark - use the proposed method.

    Signed-off-by: Ido Schimmel
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     

06 Jul, 2016

1 commit


18 May, 2016

1 commit

  • The problem is that fib_info->nh is [0] so the struct fib_info
    allocation size depends on number of nexthops. If we just copy fib_info,
    we do not copy the nexthops info and driver accesses memory which is not
    ours.

    Given the fact that fib4 does not defer operations and therefore it does
    not need copy, just pass the pointer down to drivers as it was done
    before.

    Fixes: 850d0cbc91 ("switchdev: remove pointers from switchdev objects")
    Signed-off-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Jiri Pirko
     

13 Mar, 2016

1 commit


12 Mar, 2016

1 commit

  • In rocker, ageing time is a per-port attribute, so the next time the FDB
    cleanup timer fires should be set according to the lowest ageing time.

    This will later allow us to delete the BR_MIN_AGEING_TIME macro, which was
    added to guarantee minimum ageing time in the bridge layer, thereby breaking
    existing behavior.

    Signed-off-by: Ido Schimmel
    Acked-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Ido Schimmel
     

28 Feb, 2016

1 commit

  • We intended to return PTR_ERR() here instead of 1.

    Fixes: 1f9993f6825f ('rocker: fix a neigh entry leak issue')
    Signed-off-by: Dan Carpenter
    Acked-by: Jiri Pirko
    Signed-off-by: David S. Miller

    Dan Carpenter
     

24 Feb, 2016

1 commit