Netdev List
 help / color / mirror / Atom feed
* [next-queue PATCH v6 0/5] TSN: Add qdisc based config interface for CBS
From: Vinicius Costa Gomes @ 2017-10-12  0:54 UTC (permalink / raw)
  To: netdev, intel-wired-lan
  Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri, andre.guedes,
	ivan.briano, jesus.sanchez-palencia, boon.leong.ong,
	richardcochran, henrik, levipearson, rodney.cummings

Hi,

Changes since v5:
 - Fixed comments from Jiri Pirko;

Changes since v4:
 - Added a software implementation of the CBS algorithm;

Changes since v3:
 - None, only a clean patchset without old patches;

Changes since v2:
 - squashed the patch introducing the userspace API into the patch
   implementing CBS;

Changes since v1:
 - Solved the mqprio dependency;
 - Fixed a mqprio bug, that caused the inner qdisc to have a wrong
   dev_queue associated with it;

Changes from the RFC:
 - Fixed comments from Henrik Austad;
 - Simplified the Qdisc, using the generic implementation of callbacks
   where possible;
 - Small refactor on the driver (igb) code;

This patchset is a proposal of how the Traffic Control subsystem can
be used to offload the configuration of the Credit Based Shaper
(defined in the IEEE 802.1Q-2014 Section 8.6.8.2) into supported
network devices.

As part of this work, we've assessed previous public discussions
related to TSN enabling: patches from Henrik Austad (Cisco), the
presentation from Eric Mann at Linux Plumbers 2012, patches from
Gangfeng Huang (National Instruments) and the current state of the
OpenAVNU project (https://github.com/AVnu/OpenAvnu/).

Overview
========

Time-sensitive Networking (TSN) is a set of standards that aim to
address resources availability for providing bandwidth reservation and
bounded latency on Ethernet based LANs. The proposal described here
aims to cover mainly what is needed to enable the following standards:
802.1Qat and 802.1Qav.

The initial target of this work is the Intel i210 NIC, but other
controllers' datasheet were also taken into account, like the Renesas
RZ/A1H RZ/A1M group and the Synopsis DesignWare Ethernet QoS
controller.


Proposal
========

Feature-wise, what is covered here is the configuration interfaces for
HW implementations of the Credit-Based shaper (CBS, 802.1Qav). CBS is
a per-queue shaper. Given that this feature is related to traffic
shaping, and that the traffic control subsystem already provides a
queueing discipline that offloads config into the device driver (i.e.
mqprio), designing a new qdisc for the specific purpose of offloading
the config for the CBS shaper seemed like a good fit.

For steering traffic into the correct queues, we use the socket option
SO_PRIORITY and then a mechanism to map priority to traffic classes /
Tx queues. The qdisc mqprio is currently used in our tests.

As for the CBS config interface, this patchset is proposing a new
qdisc called 'cbs'. Its 'tc' cmd line is:

$ tc qdisc add dev IFACE parent ID cbs locredit N hicredit M sendslope S \
     idleslope I

   Note that the parameters for this qdisc are the ones defined by the
   802.1Q-2014 spec, so no hardware specific functionality is exposed here.

Per-stream shaping, as defined by IEEE 802.1Q-2014 Section 34.6.1, is
not yet covered by this proposal.


Testing this RFC
================

Attached to this cover letter are:
 - calculate_cbs_params.py: A Python script to calculate the
   parameters to the CBS queueing discipline;
 - tsn-talker.c: A sample C implementation of the talker side of a stream;
 - tsn-listener.c: A sample C implementation of the listener side of a
   stream;

For testing the patches of this series, you may want to use the
attached samples to this cover letter and use the 'mqprio' qdisc to
setup the priorities to Tx queues mapping, together with the 'cbs'
qdisc to configure the HW shaper of the i210 controller:

1) Setup priorities to traffic classes to hardware queues mapping
$ tc qdisc replace dev ens4 handle 100: parent root mqprio num_tc 3 \
     map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 queues 1@0 1@1 2@2 hw 0

For a more detailed explanation, see mqprio(8), in short, this command
will map traffic with priority 3 to the hardware queue 0, traffic with
priority 2 to hardware queue 1, and the rest will be mapped to
hardware queues 2 and 3.

2) Check scheme. You want to get the inner qdiscs ID from the bottom up
$ tc -g class show dev ens4

Ex.:
+---(100:3) mqprio
|    +---(100:6) mqprio
|    +---(100:7) mqprio
|
+---(100:2) mqprio
|    +---(100:5) mqprio
|
+---(100:1) mqprio
     +---(100:4) mqprio

* Here '100:4' is Tx Queue #0 and '100:5' is Tx Queue #1.

3) Calculate CBS parameters for classes A and B. i.e. BW for A is 20Mbps and
   for B is 10Mbps:
$ calc_cbs_params.py -A 20000 -a 1500 -B 10000 -b 1500

4) Configure CBS for traffic class A (priority 3) as provided by the script:
$ tc qdisc replace dev ens4 parent 100:4 cbs locredit -1470 \
     hicredit 30 sendslope -980000 idleslope 20000

5) Configure CBS for traffic class B (priority 2):
$ tc qdisc replace dev ens4 parent 100:5 cbs \
     locredit -1485 hicredit 31 sendslope -990000 idleslope 10000

6) Run Listener:
$ ./tsn-listener -d 01:AA:AA:AA:AA:AA -i ens4 -s 1500

7) Run Talker for class A (prio 3 here), compiled from samples/tsn/talker.c
$ ./tsn-talker -d 01:AA:AA:AA:AA:AA -i ens4 -p 3 -s 1500

 * The bandwidth displayed on the listener output at this stage should be very
   close to the one configured for class A.

8) You can also run a Talker for class B (prio 2 here and using a
different address):
$ ./tsn-talker -d 01:BB:BB:BB:BB:BB -i ens4 -p 2 -s 1500


Authors
=======
 - Andre Guedes <andre.guedes@intel.com>
 - Ivan Briano <ivan.briano@intel.com>
 - Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
 - Vinicius Gomes <vinicius.gomes@intel.com>


Andre Guedes (1):
  igb: Add support for CBS offload

Jesus Sanchez-Palencia (2):
  net/sched: Check for null dev_queue on create flow
  mqprio: Implement select_queue class_ops

Vinicius Costa Gomes (2):
  net/sched: Introduce Credit Based Shaper (CBS) qdisc
  net/sched: Add support for HW offloading for CBS

 drivers/net/ethernet/intel/igb/e1000_defines.h |  23 ++
 drivers/net/ethernet/intel/igb/e1000_regs.h    |   8 +
 drivers/net/ethernet/intel/igb/igb.h           |   6 +
 drivers/net/ethernet/intel/igb/igb_main.c      | 347 ++++++++++++++++++++++
 include/linux/netdevice.h                      |   1 +
 include/net/pkt_sched.h                        |   9 +
 include/uapi/linux/pkt_sched.h                 |  18 ++
 net/sched/Kconfig                              |  11 +
 net/sched/Makefile                             |   1 +
 net/sched/sch_cbs.c                            | 382 +++++++++++++++++++++++++
 net/sched/sch_generic.c                        |   8 +-
 net/sched/sch_mqprio.c                         |   7 +
 12 files changed, 820 insertions(+), 1 deletion(-)
 create mode 100644 net/sched/sch_cbs.c


Annex: Sample files
===================

calc_cbs_params.py
--8<---------------cut here---------------start------------->8---
#!/usr/bin/env python
#
# Copyright (c) 2017, Intel Corporation
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     * Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#     * Neither the name of Intel Corporation nor the names of its contributors
#       may be used to endorse or promote products derived from this software
#       without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import argparse
import math

def print_cbs_params_for_class_a(args):
    idleslope = args.idleslope_a
    sendslope = idleslope - args.link_speed

    # According to 802.1Q-2014 spec, Annex L, hiCredit and
    # loCredit for SR class A are calculated following the
    # equations L-10 and L-12, respectively.
    hicredit = math.ceil(idleslope * args.frame_non_sr / args.link_speed)
    locredit = math.ceil(sendslope * args.frame_a / args.link_speed)

    print("tc qdisc add dev <IFNAME> parent <QDISC-ID> cbs idleslope %d sendslope %d hicredit %d locredit %d" % \
          (idleslope, sendslope, hicredit, locredit))

def print_cbs_params_for_class_b(args):
    idleslope = args.idleslope_b
    sendslope = idleslope - args.link_speed

    # Annex L doesn't present a straightforward equation to
    # calculate hiCredit for Class B so we have to derive it
    # based on generic equations presented in that Annex.
    #
    # L-3 is the primary equation to calculate hiCredit. Section
    # L.2 states that the 'maxInterferenceSize' for SR class B
    # is the maximum burst size for SR class A plus the
    # maxInterferenceSize from SR class A (which is equal to the
    # maximum frame from non-SR traffic).
    #
    # The maximum burst size for SR class A equation is shown in
    # L-16. Merging L-16 into L-3 we get the resulting equation
    # which calculates hiCredit B (refer to section L.3 in case
    # you're not familiar with the legend):
    #
    # hiCredit B = Rb * (     Mo         Ma   )
    #                     ---------- + ------
    #                      Ro - Ra       Ro
    #
    hicredit = math.ceil(idleslope * \
               ((args.frame_non_sr / (args.link_speed - args.idleslope_a)) + \
               (args.frame_a / args.link_speed)))

    # loCredit B is calculated following equation L-2.
    locredit = math.ceil(sendslope * args.frame_b / args.link_speed)

    print("tc qdisc add dev <IFNAME> parent <QDISC-ID> cbs idleslope %d sendslope %d hicredit %d locredit %d" % \
          (idleslope, sendslope, hicredit, locredit))

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument('-S', dest='link_speed', default=1000000.0, type=float,
                        help='Link speed in kbps')
    parser.add_argument('-s', dest='frame_non_sr', default=1500.0, type=float,
                        help='Maximum frame size from non-SR traffic (MTU size'
                        'usually')
    parser.add_argument('-A', dest='idleslope_a', default=0, type=float,
                        help='Idleslope for SR class A in kbps')
    parser.add_argument('-a', dest='frame_a', default=0, type=float,
                        help='Maximum frame size for SR class A traffic')
    parser.add_argument('-B', dest='idleslope_b', default=0, type=float,
                        help='Idleslope for SR class B in kbps')
    parser.add_argument('-b', dest='frame_b', default=0, type=float,
                        help='Maximum frame size for SR class B traffic')

    args = parser.parse_args()

    if args.idleslope_a > 0:
        print_cbs_params_for_class_a(args)

    if args.idleslope_b > 0:
        print_cbs_params_for_class_b(args)

if __name__ == "__main__":
    main()
--8<---------------cut here---------------end--------------->8---

tsn-talker.c
--8<---------------cut here---------------start------------->8---
/*
 * Copyright (c) 2017, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Intel Corporation nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <alloca.h>
#include <argp.h>
#include <arpa/inet.h>
#include <inttypes.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define MAGIC 0xCC

static uint8_t ifname[IFNAMSIZ];
static uint8_t macaddr[ETH_ALEN];
static int priority = -1;
static size_t size = 1500;
static uint64_t seq;
static int delay = -1;

static struct argp_option options[] = {
	{"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" },
	{"delay", 'D', "NUM", 0, "Delay (in us) between packet transmission" },
	{"ifname", 'i', "IFNAME", 0, "Network Interface" },
	{"prio", 'p', "NUM", 0, "SO_PRIORITY to be set in socket" },
	{"packet-size", 's', "NUM", 0, "Size of packets to be transmitted" },
	{ 0 }
};

static error_t parser(int key, char *arg, struct argp_state *state)
{
	int res;

	switch (key) {
	case 'd':
		res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
					&macaddr[0], &macaddr[1], &macaddr[2],
					&macaddr[3], &macaddr[4], &macaddr[5]);
		if (res != 6) {
			printf("Invalid address\n");
			exit(EXIT_FAILURE);
		}

		break;
	case 'D':
		delay = atoi(arg);
		break;
	case 'i':
		strncpy(ifname, arg, sizeof(ifname) - 1);
		break;
	case 'p':
		priority = atoi(arg);
		break;
	case 's':
		size = atoi(arg);
		break;
	}

	return 0;
}

static struct argp argp = { options, parser };

int main(int argc, char *argv[])
{
	int fd, res;
	struct ifreq req;
	uint8_t *data;
	struct sockaddr_ll sk_addr = {
		.sll_family = AF_PACKET,
		.sll_protocol = htons(ETH_P_TSN),
		.sll_halen = ETH_ALEN,
	};

	argp_parse(&argp, argc, argv, 0, NULL, NULL);

	fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_TSN));
	if (fd < 0) {
		perror("Couldn't open socket");
		return 1;
	}

	strncpy(req.ifr_name, ifname, sizeof(req.ifr_name));
	res = ioctl(fd, SIOCGIFINDEX, &req);
	if (res < 0) {
		perror("Couldn't get interface index");
		goto err;
	}

	sk_addr.sll_ifindex = req.ifr_ifindex;
	memcpy(&sk_addr.sll_addr, macaddr, ETH_ALEN);

	if (priority != -1) {
		res = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority,
							sizeof(priority));
		if (res < 0) {
			perror("Couldn't set priority");
			goto err;
		}

	}

	data = alloca(size);
	memset(data, MAGIC, size);

	printf("Sending packets...\n");

	while (1) {
		uint64_t *seq_ptr = (uint64_t *) &data[0];
		ssize_t n;

		*seq_ptr = seq++;

		n = sendto(fd, data, size, 0, (struct sockaddr *) &sk_addr,
							sizeof(sk_addr));
		if (n < 0)
			perror("Failed to send data");

		if (delay > 0)
			usleep(delay);
	}

	close(fd);
	return 0;

err:
	close(fd);
	return 1;
}
--8<---------------cut here---------------end--------------->8---

tsn-listener.c
--8<---------------cut here---------------start------------->8---
/*
 * Copyright (c) 2017, Intel Corporation
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Intel Corporation nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <alloca.h>
#include <argp.h>
#include <arpa/inet.h>
#include <inttypes.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/timerfd.h>
#include <unistd.h>

static uint8_t ifname[IFNAMSIZ];
static uint8_t macaddr[ETH_ALEN];
static uint64_t data_count;
static int size = 1500;
static time_t interval = 1;
static bool check_seq = false;
static uint64_t expected_seq;

static struct argp_option options[] = {
	{"check-seq", 'c', NULL, 0, "Check sequence number within packet" },
	{"dst-addr", 'd', "MACADDR", 0, "Stream Destination MAC address" },
	{"ifname", 'i', "IFNAME", 0, "Network Interface" },
	{"interval", 'I', "SEC", 0, "Interval between bandwidth reports" },
	{"packet-size", 's', "NUM", 0, "Expected packet size" },
	{ 0 }
};

static error_t parser(int key, char *arg, struct argp_state *state)
{
	int res;

	switch (key) {
	case 'c':
		check_seq = true;
		break;
	case 'd':
		res = sscanf(arg, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
					&macaddr[0], &macaddr[1], &macaddr[2],
					&macaddr[3], &macaddr[4], &macaddr[5]);
		if (res != 6) {
			printf("Invalid address\n");
			exit(EXIT_FAILURE);
		}

		break;
	case 'i':
		strncpy(ifname, arg, sizeof(ifname) - 1);
		break;
	case 'I':
		interval = atoi(arg);
		break;
	case 's':
		size = atoi(arg);
		break;
	}

	return 0;
}

static struct argp argp = { options, parser };

static int setup_timer(void)
{
	int fd, res;
	struct itimerspec tspec = { 0 };

	fd = timerfd_create(CLOCK_MONOTONIC, 0);
	if (fd < 0) {
		perror("Couldn't create timer");
		return -1;
	}

	tspec.it_value.tv_sec = interval;
	tspec.it_interval.tv_sec = interval;

	res = timerfd_settime(fd, 0, &tspec, NULL);
	if (res < 0) {
		perror("Couldn't set timer");
		close(fd);
		return -1;
	}

	return fd;
}

static int setup_socket(void)
{
	int fd, res;
	struct sockaddr_ll sk_addr = {
		.sll_family = AF_PACKET,
		.sll_protocol = htons(ETH_P_TSN),
	};

	fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_TSN));
	if (fd < 0) {
		perror("Couldn't open socket");
		return -1;
	}

	/* If user provided a network interface, bind() to it. */
	if (ifname[0] != '\0') {
		struct ifreq req;

		strncpy(req.ifr_name, ifname, sizeof(req.ifr_name));
		res = ioctl(fd, SIOCGIFINDEX, &req);
		if (res < 0) {
			perror("Couldn't get interface index");
			goto err;
		}

		sk_addr.sll_ifindex = req.ifr_ifindex;

		res = bind(fd, (struct sockaddr *) &sk_addr, sizeof(sk_addr));
		if (res < 0) {
			perror("Couldn't bind() to interface");
			goto err;
		}
	}

	/* If user provided the stream destination address, set it as multicast
	 * address.
	 */
	if (macaddr[0] != '\0') {
		struct packet_mreq mreq;

		mreq.mr_ifindex = sk_addr.sll_ifindex;
		mreq.mr_type = PACKET_MR_MULTICAST;
		mreq.mr_alen = ETH_ALEN;
		memcpy(&mreq.mr_address, macaddr, ETH_ALEN);

		res = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
					&mreq, sizeof(struct packet_mreq));
		if (res < 0) {
			perror("Couldn't set PACKET_ADD_MEMBERSHIP");
			goto err;
		}
	}

	return fd;

err:
	close(fd);
	return -1;
}

static void recv_packet(int fd)
{
	uint8_t *data = alloca(size);
	ssize_t n = recv(fd, data, size, 0);

	if (n < 0) {
		perror("Failed to receive data");
		return;
	}

	if (n != size)
		printf("Size mismatch: expected %d, got %d\n", size, n);

	if (check_seq) {
		uint64_t *seq = (uint64_t *) &data[0];

		/* If 'expected_seq' is equal to zero, it means this is the
		 * first packet we received so we don't know what sequence
		 * number to expect.
		 */
		if (expected_seq == 0)
			expected_seq = *seq;

		if (*seq != expected_seq) {
			printf("Sequence mismatch: expected %llu, got %llu\n",
					expected_seq, *seq);

			expected_seq = *seq;
		}

		expected_seq++;
	}

	data_count += n;
}

static void report_bw(int fd)
{
	uint64_t expirations;
	ssize_t n = read(fd, &expirations, sizeof(uint64_t));

	if (n < 0) {
		perror("Couldn't read timerfd");
		return;
	}

	if (expirations != 1)
		printf("Some went wrong with timerfd\n");

	printf("Receiving data rate: %llu kbps\n", (data_count * 8) / (1000 * interval));

	data_count = 0;
}

int main(int argc, char *argv[])
{
	int sk_fd, timer_fd, res;
	struct pollfd fds[2];

	argp_parse(&argp, argc, argv, 0, NULL, NULL);

	sk_fd = setup_socket();
	if (sk_fd < 0)
		return 1;

	timer_fd = setup_timer();
	if (timer_fd < 0) {
		close(sk_fd);
		return 1;
	}

	fds[0].fd = sk_fd;
	fds[0].events = POLLIN;
	fds[1].fd = timer_fd;
	fds[1].events = POLLIN;

	printf("Waiting for packets...\n");

	while (1) {
		res = poll(fds, 2, -1);
		if (res < 0) {
			perror("Error on poll()");
			goto err;
		}

		if (fds[0].revents & POLLIN)
			recv_packet(fds[0].fd);

		if (fds[1].revents & POLLIN) {
			report_bw(fds[1].fd);
		}
	}

	close(timer_fd);
	close(sk_fd);
	return 0;

err:
	close(timer_fd);
	close(sk_fd);
	return 1;
}
--8<---------------cut here---------------end--------------->8---

^ permalink raw reply

* [next-queue PATCH v6 1/5] net/sched: Check for null dev_queue on create flow
From: Vinicius Costa Gomes @ 2017-10-12  0:54 UTC (permalink / raw)
  To: netdev, intel-wired-lan
  Cc: Jesus Sanchez-Palencia, jhs, xiyou.wangcong, jiri, andre.guedes,
	ivan.briano, boon.leong.ong, richardcochran, henrik, levipearson,
	rodney.cummings
In-Reply-To: <20171012005449.26533-1-vinicius.gomes@intel.com>

From: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>

In qdisc_alloc() the dev_queue pointer was used without any checks
being performed. If qdisc_create() gets a null dev_queue pointer, it
just passes it along to qdisc_alloc(), leading to a crash. That
happens if a root qdisc implements select_queue() and returns a null
dev_queue pointer for an "invalid handle", for example, or if the
dev_queue associated with the parent qdisc is null.

This patch is in preparation for the next in this series, where
select_queue() is being added to mqprio and as it may return a null
dev_queue.

Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
---
 net/sched/sch_generic.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index a0a198768aad..de2408f1ccd3 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -603,8 +603,14 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
 	struct Qdisc *sch;
 	unsigned int size = QDISC_ALIGN(sizeof(*sch)) + ops->priv_size;
 	int err = -ENOBUFS;
-	struct net_device *dev = dev_queue->dev;
+	struct net_device *dev;
+
+	if (!dev_queue) {
+		err = -EINVAL;
+		goto errout;
+	}
 
+	dev = dev_queue->dev;
 	p = kzalloc_node(size, GFP_KERNEL,
 			 netdev_queue_numa_node_read(dev_queue));
 
-- 
2.14.2

^ permalink raw reply related

* [PATCH net-next v2 7/7] net: qualcomm: rmnet: Implement bridge mode
From: Subash Abhinov Kasiviswanathan @ 2017-10-12  0:43 UTC (permalink / raw)
  To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1507769038-30231-1-git-send-email-subashab@codeaurora.org>

Add support to bridge two devices which can send multiplexing and
aggregation (MAP) data. This is done only when the data itself is
not going to be consumed in the stack but is being passed on to a
different endpoint. This is mainly used for testing.

Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 93 +++++++++++++++++++++-
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h |  7 +-
 .../net/ethernet/qualcomm/rmnet/rmnet_handlers.c   | 26 +++++-
 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c    |  2 +
 4 files changed, 122 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index b5fe3f4..71bee1a 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -109,6 +109,36 @@ static int rmnet_register_real_device(struct net_device *real_dev)
 	return 0;
 }
 
+static void rmnet_unregister_bridge(struct net_device *dev,
+				    struct rmnet_port *port)
+{
+	struct net_device *rmnet_dev, *bridge_dev;
+	struct rmnet_port *bridge_port;
+
+	if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
+		return;
+
+	/* bridge slave handling */
+	if (!port->nr_rmnet_devs) {
+		rmnet_dev = netdev_master_upper_dev_get_rcu(dev);
+		netdev_upper_dev_unlink(dev, rmnet_dev);
+
+		bridge_dev = port->bridge_ep;
+
+		bridge_port = rmnet_get_port_rtnl(bridge_dev);
+		bridge_port->bridge_ep = NULL;
+		bridge_port->rmnet_mode = RMNET_EPMODE_VND;
+	} else {
+		bridge_dev = port->bridge_ep;
+
+		bridge_port = rmnet_get_port_rtnl(bridge_dev);
+		rmnet_dev = netdev_master_upper_dev_get_rcu(bridge_dev);
+		netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
+
+		rmnet_unregister_real_device(bridge_dev, bridge_port);
+	}
+}
+
 static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 			 struct nlattr *tb[], struct nlattr *data[],
 			 struct netlink_ext_ack *extack)
@@ -190,10 +220,10 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 	ep = rmnet_get_endpoint(port, mux_id);
 	if (ep) {
 		hlist_del_init_rcu(&ep->hlnode);
+		rmnet_unregister_bridge(dev, port);
 		rmnet_vnd_dellink(mux_id, port, ep);
 		kfree(ep);
 	}
-
 	rmnet_unregister_real_device(real_dev, port);
 
 	unregister_netdevice_queue(dev, head);
@@ -237,6 +267,8 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
 	d.port = port;
 
 	rcu_read_lock();
+	rmnet_unregister_bridge(dev, port);
+
 	netdev_walk_all_lower_dev_rcu(real_dev, rmnet_dev_walk_unreg, &d);
 	rcu_read_unlock();
 	unregister_netdevice_many(&list);
@@ -321,6 +353,65 @@ struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id)
 	return NULL;
 }
 
+int rmnet_add_bridge(struct net_device *rmnet_dev,
+		     struct net_device *slave_dev,
+		     struct netlink_ext_ack *extack)
+{
+	struct rmnet_priv *priv = netdev_priv(rmnet_dev);
+	struct net_device *real_dev = priv->real_dev;
+	struct rmnet_port *port, *slave_port;
+	int err;
+
+	port = rmnet_get_port(real_dev);
+
+	/* If there is more than one rmnet dev attached, its probably being
+	 * used for muxing. Skip the briding in that case
+	 */
+	if (port->nr_rmnet_devs > 1)
+		return -EINVAL;
+
+	if (rmnet_is_real_dev_registered(slave_dev))
+		return -EBUSY;
+
+	err = rmnet_register_real_device(slave_dev);
+	if (err)
+		return -EBUSY;
+
+	err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
+					   extack);
+	if (err)
+		return -EINVAL;
+
+	slave_port = rmnet_get_port(slave_dev);
+	slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
+	slave_port->bridge_ep = real_dev;
+
+	port->rmnet_mode = RMNET_EPMODE_BRIDGE;
+	port->bridge_ep = slave_dev;
+
+	netdev_dbg(slave_dev, "registered with rmnet as slave\n");
+	return 0;
+}
+
+int rmnet_del_bridge(struct net_device *rmnet_dev,
+		     struct net_device *slave_dev)
+{
+	struct rmnet_priv *priv = netdev_priv(rmnet_dev);
+	struct net_device *real_dev = priv->real_dev;
+	struct rmnet_port *port, *slave_port;
+
+	port = rmnet_get_port(real_dev);
+	port->rmnet_mode = RMNET_EPMODE_VND;
+	port->bridge_ep = NULL;
+
+	netdev_upper_dev_unlink(slave_dev, rmnet_dev);
+	slave_port = rmnet_get_port(slave_dev);
+	rmnet_unregister_real_device(slave_dev, slave_port);
+
+	netdev_dbg(slave_dev, "removed from rmnet as slave\n");
+	return 0;
+}
+
 /* Startup/Shutdown */
 
 static int __init rmnet_init(void)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index 8849986..60115e6 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -36,6 +36,7 @@ struct rmnet_port {
 	u8 nr_rmnet_devs;
 	u8 rmnet_mode;
 	struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
+	struct net_device *bridge_ep;
 };
 
 extern struct rtnl_link_ops rmnet_link_ops;
@@ -47,5 +48,9 @@ struct rmnet_priv {
 
 struct rmnet_port *rmnet_get_port(struct net_device *real_dev);
 struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id);
-
+int rmnet_add_bridge(struct net_device *rmnet_dev,
+		     struct net_device *slave_dev,
+		     struct netlink_ext_ack *extack);
+int rmnet_del_bridge(struct net_device *rmnet_dev,
+		     struct net_device *slave_dev);
 #endif /* _RMNET_CONFIG_H_ */
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index fa24ffb..df3d2d1 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -149,6 +149,17 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
 	return RMNET_MAP_SUCCESS;
 }
 
+static rx_handler_result_t
+rmnet_bridge_handler(struct sk_buff *skb, struct net_device *bridge_dev)
+{
+	if (bridge_dev) {
+		skb->dev = bridge_dev;
+		dev_queue_xmit(skb);
+	}
+
+	return RX_HANDLER_CONSUMED;
+}
+
 /* Ingress / Egress Entry Points */
 
 /* Processes packet as per ingress data format for receiving device. Logical
@@ -157,10 +168,10 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
  */
 rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
 {
-	struct rmnet_port *port;
+	int rc = RX_HANDLER_CONSUMED;
 	struct sk_buff *skb = *pskb;
+	struct rmnet_port *port;
 	struct net_device *dev;
-	int rc;
 
 	if (!skb)
 		return RX_HANDLER_CONSUMED;
@@ -168,8 +179,15 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
 	dev = skb->dev;
 	port = rmnet_get_port(dev);
 
-	if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP)
-		rc = rmnet_map_ingress_handler(skb, port);
+	switch (port->rmnet_mode) {
+	case RMNET_EPMODE_VND:
+		if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP)
+			rc = rmnet_map_ingress_handler(skb, port);
+		break;
+	case RMNET_EPMODE_BRIDGE:
+		rc = rmnet_bridge_handler(skb, port->bridge_ep);
+		break;
+	}
 
 	return rc;
 }
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index 1b6747d..12bd0bb 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -74,6 +74,8 @@ static int rmnet_vnd_get_iflink(const struct net_device *dev)
 	.ndo_start_xmit = rmnet_vnd_start_xmit,
 	.ndo_change_mtu = rmnet_vnd_change_mtu,
 	.ndo_get_iflink = rmnet_vnd_get_iflink,
+	.ndo_add_slave  = rmnet_add_bridge,
+	.ndo_del_slave  = rmnet_del_bridge,
 };
 
 /* Called by kernel whenever a new rmnet<n> device is created. Sets MTU,
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next v2 6/7] net: qualcomm: rmnet: Convert the muxed endpoint to hlist
From: Subash Abhinov Kasiviswanathan @ 2017-10-12  0:43 UTC (permalink / raw)
  To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan, Dan Williams
In-Reply-To: <1507769038-30231-1-git-send-email-subashab@codeaurora.org>

Rather than using a static array, use a hlist to store the muxed
endpoints and use the mux id to query the rmnet_device.
This is useful as usually very few mux ids are used.

Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Cc: Dan Williams <dcbw@redhat.com>
---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 75 ++++++++++++----------
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h |  4 +-
 .../net/ethernet/qualcomm/rmnet/rmnet_handlers.c   | 17 +++--
 .../ethernet/qualcomm/rmnet/rmnet_map_command.c    |  4 +-
 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c    | 15 +++--
 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h    |  6 +-
 6 files changed, 68 insertions(+), 53 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 96058bb..b5fe3f4 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -61,18 +61,6 @@ static int rmnet_is_real_dev_registered(const struct net_device *real_dev)
 	return rtnl_dereference(real_dev->rx_handler_data);
 }
 
-static struct rmnet_endpoint*
-rmnet_get_endpoint(struct net_device *dev, int config_id)
-{
-	struct rmnet_endpoint *ep;
-	struct rmnet_port *port;
-
-	port = rmnet_get_port_rtnl(dev);
-	ep = &port->muxed_ep[config_id];
-
-	return ep;
-}
-
 static int rmnet_unregister_real_device(struct net_device *real_dev,
 					struct rmnet_port *port)
 {
@@ -93,7 +81,7 @@ static int rmnet_unregister_real_device(struct net_device *real_dev,
 static int rmnet_register_real_device(struct net_device *real_dev)
 {
 	struct rmnet_port *port;
-	int rc;
+	int rc, entry;
 
 	ASSERT_RTNL();
 
@@ -114,26 +102,13 @@ static int rmnet_register_real_device(struct net_device *real_dev)
 	/* hold on to real dev for MAP data */
 	dev_hold(real_dev);
 
+	for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++)
+		INIT_HLIST_HEAD(&port->muxed_ep[entry]);
+
 	netdev_dbg(real_dev, "registered with rmnet\n");
 	return 0;
 }
 
-static void rmnet_set_endpoint_config(struct net_device *dev,
-				      u8 mux_id, struct net_device *egress_dev)
-{
-	struct rmnet_endpoint *ep;
-
-	netdev_dbg(dev, "id %d dev %s\n", mux_id, egress_dev->name);
-
-	ep = rmnet_get_endpoint(dev, mux_id);
-	/* This config is cleared on every set, so its ok to not
-	 * clear it on a device delete.
-	 */
-	memset(ep, 0, sizeof(struct rmnet_endpoint));
-	ep->egress_dev = egress_dev;
-	ep->mux_id = mux_id;
-}
-
 static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 			 struct nlattr *tb[], struct nlattr *data[],
 			 struct netlink_ext_ack *extack)
@@ -145,6 +120,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 			    RMNET_EGRESS_FORMAT_MAP;
 	struct net_device *real_dev;
 	int mode = RMNET_EPMODE_VND;
+	struct rmnet_endpoint *ep;
 	struct rmnet_port *port;
 	int err = 0;
 	u16 mux_id;
@@ -156,6 +132,10 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 	if (!data[IFLA_VLAN_ID])
 		return -EINVAL;
 
+	ep = kzalloc(sizeof(*ep), GFP_ATOMIC);
+	if (!ep)
+		return -ENOMEM;
+
 	mux_id = nla_get_u16(data[IFLA_VLAN_ID]);
 
 	err = rmnet_register_real_device(real_dev);
@@ -163,7 +143,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 		goto err0;
 
 	port = rmnet_get_port_rtnl(real_dev);
-	err = rmnet_vnd_newlink(mux_id, dev, port, real_dev);
+	err = rmnet_vnd_newlink(mux_id, dev, port, real_dev, ep);
 	if (err)
 		goto err1;
 
@@ -177,11 +157,11 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 	port->ingress_data_format = ingress_format;
 	port->rmnet_mode = mode;
 
-	rmnet_set_endpoint_config(real_dev, mux_id, dev);
+	hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
 	return 0;
 
 err2:
-	rmnet_vnd_dellink(mux_id, port);
+	rmnet_vnd_dellink(mux_id, port, ep);
 err1:
 	rmnet_unregister_real_device(real_dev, port);
 err0:
@@ -191,6 +171,7 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 {
 	struct net_device *real_dev;
+	struct rmnet_endpoint *ep;
 	struct rmnet_port *port;
 	u8 mux_id;
 
@@ -204,8 +185,15 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 	port = rmnet_get_port_rtnl(real_dev);
 
 	mux_id = rmnet_vnd_get_mux(dev);
-	rmnet_vnd_dellink(mux_id, port);
 	netdev_upper_dev_unlink(dev, real_dev);
+
+	ep = rmnet_get_endpoint(port, mux_id);
+	if (ep) {
+		hlist_del_init_rcu(&ep->hlnode);
+		rmnet_vnd_dellink(mux_id, port, ep);
+		kfree(ep);
+	}
+
 	rmnet_unregister_real_device(real_dev, port);
 
 	unregister_netdevice_queue(dev, head);
@@ -214,11 +202,16 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data)
 {
 	struct rmnet_walk_data *d = data;
+	struct rmnet_endpoint *ep;
 	u8 mux_id;
 
 	mux_id = rmnet_vnd_get_mux(rmnet_dev);
-
-	rmnet_vnd_dellink(mux_id, d->port);
+	ep = rmnet_get_endpoint(d->port, mux_id);
+	if (ep) {
+		hlist_del_init_rcu(&ep->hlnode);
+		rmnet_vnd_dellink(mux_id, d->port, ep);
+		kfree(ep);
+	}
 	netdev_upper_dev_unlink(rmnet_dev, d->real_dev);
 	unregister_netdevice_queue(rmnet_dev, d->head);
 
@@ -316,6 +309,18 @@ struct rmnet_port *rmnet_get_port(struct net_device *real_dev)
 		return NULL;
 }
 
+struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id)
+{
+	struct rmnet_endpoint *ep;
+
+	hlist_for_each_entry_rcu(ep, &port->muxed_ep[mux_id], hlnode) {
+		if (ep->mux_id == mux_id)
+			return ep;
+	}
+
+	return NULL;
+}
+
 /* Startup/Shutdown */
 
 static int __init rmnet_init(void)
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index 123ccf4..8849986 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -23,6 +23,7 @@
 struct rmnet_endpoint {
 	u8 mux_id;
 	struct net_device *egress_dev;
+	struct hlist_node hlnode;
 };
 
 /* One instance of this structure is instantiated for each real_dev associated
@@ -30,11 +31,11 @@ struct rmnet_endpoint {
  */
 struct rmnet_port {
 	struct net_device *dev;
-	struct rmnet_endpoint muxed_ep[RMNET_MAX_LOGICAL_EP];
 	u32 ingress_data_format;
 	u32 egress_data_format;
 	u8 nr_rmnet_devs;
 	u8 rmnet_mode;
+	struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
 };
 
 extern struct rtnl_link_ops rmnet_link_ops;
@@ -45,5 +46,6 @@ struct rmnet_priv {
 };
 
 struct rmnet_port *rmnet_get_port(struct net_device *real_dev);
+struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id);
 
 #endif /* _RMNET_CONFIG_H_ */
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index e0802d3..fa24ffb 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -71,19 +71,18 @@ static void rmnet_set_skb_proto(struct sk_buff *skb)
 		    & RMNET_INGRESS_FORMAT_MAP_COMMANDS)
 			return rmnet_map_command(skb, port);
 
-		kfree_skb(skb);
-		return RX_HANDLER_CONSUMED;
+		goto free_skb;
 	}
 
 	mux_id = RMNET_MAP_GET_MUX_ID(skb);
 	len = RMNET_MAP_GET_LENGTH(skb) - RMNET_MAP_GET_PAD(skb);
 
-	if (mux_id >= RMNET_MAX_LOGICAL_EP) {
-		kfree_skb(skb);
-		return RX_HANDLER_CONSUMED;
-	}
+	if (mux_id >= RMNET_MAX_LOGICAL_EP)
+		goto free_skb;
 
-	ep = &port->muxed_ep[mux_id];
+	ep = rmnet_get_endpoint(port, mux_id);
+	if (!ep)
+		goto free_skb;
 
 	if (port->ingress_data_format & RMNET_INGRESS_FORMAT_DEMUXING)
 		skb->dev = ep->egress_dev;
@@ -93,6 +92,10 @@ static void rmnet_set_skb_proto(struct sk_buff *skb)
 	skb_trim(skb, len);
 	rmnet_set_skb_proto(skb);
 	return rmnet_deliver_skb(skb);
+
+free_skb:
+	kfree_skb(skb);
+	return RX_HANDLER_CONSUMED;
 }
 
 static rx_handler_result_t
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
index d1ea5e2..74d362f 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
@@ -17,7 +17,7 @@
 #include "rmnet_vnd.h"
 
 static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
-				    struct rmnet_port *rdinfo,
+				    struct rmnet_port *port,
 				    int enable)
 {
 	struct rmnet_map_control_command *cmd;
@@ -37,7 +37,7 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
 		return RX_HANDLER_CONSUMED;
 	}
 
-	ep = &rdinfo->muxed_ep[mux_id];
+	ep = rmnet_get_endpoint(port, mux_id);
 	vnd = ep->egress_dev;
 
 	ip_family = cmd->flow_control.ip_family;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index 8b8497b..1b6747d 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -100,17 +100,19 @@ void rmnet_vnd_setup(struct net_device *rmnet_dev)
 
 int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
 		      struct rmnet_port *port,
-		      struct net_device *real_dev)
+		      struct net_device *real_dev,
+		      struct rmnet_endpoint *ep)
 {
 	struct rmnet_priv *priv;
 	int rc;
 
-	if (port->muxed_ep[id].egress_dev)
+	if (ep->egress_dev)
 		return -EINVAL;
 
 	rc = register_netdevice(rmnet_dev);
 	if (!rc) {
-		port->muxed_ep[id].egress_dev = rmnet_dev;
+		ep->egress_dev = rmnet_dev;
+		ep->mux_id = id;
 		port->nr_rmnet_devs++;
 
 		rmnet_dev->rtnl_link_ops = &rmnet_link_ops;
@@ -125,12 +127,13 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
 	return rc;
 }
 
-int rmnet_vnd_dellink(u8 id, struct rmnet_port *port)
+int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
+		      struct rmnet_endpoint *ep)
 {
-	if (id >= RMNET_MAX_LOGICAL_EP || !port->muxed_ep[id].egress_dev)
+	if (id >= RMNET_MAX_LOGICAL_EP || !ep->egress_dev)
 		return -EINVAL;
 
-	port->muxed_ep[id].egress_dev = NULL;
+	ep->egress_dev = NULL;
 	port->nr_rmnet_devs--;
 	return 0;
 }
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
index cae134d..71e4c32 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
@@ -19,8 +19,10 @@
 int rmnet_vnd_do_flow_control(struct net_device *dev, int enable);
 int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
 		      struct rmnet_port *port,
-		      struct net_device *real_dev);
-int rmnet_vnd_dellink(u8 id, struct rmnet_port *port);
+		      struct net_device *real_dev,
+		      struct rmnet_endpoint *ep);
+int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
+		      struct rmnet_endpoint *ep);
 void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
 void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
 u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev);
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next v2 5/7] net: qualcomm: rmnet: Remove duplicate setting of rmnet_devices
From: Subash Abhinov Kasiviswanathan @ 2017-10-12  0:43 UTC (permalink / raw)
  To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1507769038-30231-1-git-send-email-subashab@codeaurora.org>

The rmnet_devices information is already stored in muxed_ep, so
storing this in rmnet_devices[] again is redundant.

Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h | 1 -
 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c    | 8 ++++----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index c5f5c6d..123ccf4 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -33,7 +33,6 @@ struct rmnet_port {
 	struct rmnet_endpoint muxed_ep[RMNET_MAX_LOGICAL_EP];
 	u32 ingress_data_format;
 	u32 egress_data_format;
-	struct net_device *rmnet_devices[RMNET_MAX_LOGICAL_EP];
 	u8 nr_rmnet_devs;
 	u8 rmnet_mode;
 };
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index 4ca59a4..8b8497b 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -105,12 +105,12 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
 	struct rmnet_priv *priv;
 	int rc;
 
-	if (port->rmnet_devices[id])
+	if (port->muxed_ep[id].egress_dev)
 		return -EINVAL;
 
 	rc = register_netdevice(rmnet_dev);
 	if (!rc) {
-		port->rmnet_devices[id] = rmnet_dev;
+		port->muxed_ep[id].egress_dev = rmnet_dev;
 		port->nr_rmnet_devs++;
 
 		rmnet_dev->rtnl_link_ops = &rmnet_link_ops;
@@ -127,10 +127,10 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
 
 int rmnet_vnd_dellink(u8 id, struct rmnet_port *port)
 {
-	if (id >= RMNET_MAX_LOGICAL_EP || !port->rmnet_devices[id])
+	if (id >= RMNET_MAX_LOGICAL_EP || !port->muxed_ep[id].egress_dev)
 		return -EINVAL;
 
-	port->rmnet_devices[id] = NULL;
+	port->muxed_ep[id].egress_dev = NULL;
 	port->nr_rmnet_devs--;
 	return 0;
 }
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next v2 4/7] net: qualcomm: rmnet: Remove duplicate setting of rmnet private info
From: Subash Abhinov Kasiviswanathan @ 2017-10-12  0:43 UTC (permalink / raw)
  To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1507769038-30231-1-git-send-email-subashab@codeaurora.org>

The end point is set twice in the local_ep as well as the mux_id and
the real_dev in the rmnet private structure. Remove the local_ep.
While these elements are equivalent, rmnet_endpoint will be
used only as part of the rmnet_port for muxed scenarios in VND mode.

Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c   | 10 ++--------
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h   |  4 ----
 drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c | 18 ++++++++++--------
 drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h |  3 +--
 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c      | 19 ++-----------------
 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h      |  1 -
 6 files changed, 15 insertions(+), 40 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 85fce9c..96058bb 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -67,13 +67,8 @@ static int rmnet_is_real_dev_registered(const struct net_device *real_dev)
 	struct rmnet_endpoint *ep;
 	struct rmnet_port *port;
 
-	if (!rmnet_is_real_dev_registered(dev)) {
-		ep = rmnet_vnd_get_endpoint(dev);
-	} else {
-		port = rmnet_get_port_rtnl(dev);
-
-		ep = &port->muxed_ep[config_id];
-	}
+	port = rmnet_get_port_rtnl(dev);
+	ep = &port->muxed_ep[config_id];
 
 	return ep;
 }
@@ -183,7 +178,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 	port->rmnet_mode = mode;
 
 	rmnet_set_endpoint_config(real_dev, mux_id, dev);
-	rmnet_set_endpoint_config(dev, mux_id, real_dev);
 	return 0;
 
 err2:
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index 03d473f..c5f5c6d 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -20,9 +20,6 @@
 
 #define RMNET_MAX_LOGICAL_EP 255
 
-/* Information about the next device to deliver the packet to.
- * Exact usage of this parameter depends on the rmnet_mode.
- */
 struct rmnet_endpoint {
 	u8 mux_id;
 	struct net_device *egress_dev;
@@ -44,7 +41,6 @@ struct rmnet_port {
 extern struct rtnl_link_ops rmnet_link_ops;
 
 struct rmnet_priv {
-	struct rmnet_endpoint local_ep;
 	u8 mux_id;
 	struct net_device *real_dev;
 };
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index 86e37cc..e0802d3 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -116,8 +116,7 @@ static void rmnet_set_skb_proto(struct sk_buff *skb)
 }
 
 static int rmnet_map_egress_handler(struct sk_buff *skb,
-				    struct rmnet_port *port,
-				    struct rmnet_endpoint *ep,
+				    struct rmnet_port *port, u8 mux_id,
 				    struct net_device *orig_dev)
 {
 	int required_headroom, additional_header_len;
@@ -136,10 +135,10 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
 		return RMNET_MAP_CONSUMED;
 
 	if (port->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) {
-		if (ep->mux_id == 0xff)
+		if (mux_id == 0xff)
 			map_header->mux_id = 0;
 		else
-			map_header->mux_id = ep->mux_id;
+			map_header->mux_id = mux_id;
 	}
 
 	skb->protocol = htons(ETH_P_MAP);
@@ -176,14 +175,17 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
  * for egress device configured in logical endpoint. Packet is then transmitted
  * on the egress device.
  */
-void rmnet_egress_handler(struct sk_buff *skb,
-			  struct rmnet_endpoint *ep)
+void rmnet_egress_handler(struct sk_buff *skb)
 {
 	struct net_device *orig_dev;
 	struct rmnet_port *port;
+	struct rmnet_priv *priv;
+	u8 mux_id;
 
 	orig_dev = skb->dev;
-	skb->dev = ep->egress_dev;
+	priv = netdev_priv(orig_dev);
+	skb->dev = priv->real_dev;
+	mux_id = priv->mux_id;
 
 	port = rmnet_get_port(skb->dev);
 	if (!port) {
@@ -192,7 +194,7 @@ void rmnet_egress_handler(struct sk_buff *skb,
 	}
 
 	if (port->egress_data_format & RMNET_EGRESS_FORMAT_MAP) {
-		switch (rmnet_map_egress_handler(skb, port, ep, orig_dev)) {
+		switch (rmnet_map_egress_handler(skb, port, mux_id, orig_dev)) {
 		case RMNET_MAP_CONSUMED:
 			return;
 
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h
index f2638cf..3537e4c 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.h
@@ -18,8 +18,7 @@
 
 #include "rmnet_config.h"
 
-void rmnet_egress_handler(struct sk_buff *skb,
-			  struct rmnet_endpoint *ep);
+void rmnet_egress_handler(struct sk_buff *skb);
 
 rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb);
 
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index 7f90d55..4ca59a4 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -45,8 +45,8 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
 	struct rmnet_priv *priv;
 
 	priv = netdev_priv(dev);
-	if (priv->local_ep.egress_dev) {
-		rmnet_egress_handler(skb, &priv->local_ep);
+	if (priv->real_dev) {
+		rmnet_egress_handler(skb);
 	} else {
 		dev->stats.tx_dropped++;
 		kfree_skb(skb);
@@ -143,21 +143,6 @@ u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev)
 	return priv->mux_id;
 }
 
-/* Gets the logical endpoint configuration for a RmNet virtual network device
- * node. Caller should confirm that devices is a RmNet VND before calling.
- */
-struct rmnet_endpoint *rmnet_vnd_get_endpoint(struct net_device *rmnet_dev)
-{
-	struct rmnet_priv *priv;
-
-	if (!rmnet_dev)
-		return NULL;
-
-	priv = netdev_priv(rmnet_dev);
-
-	return &priv->local_ep;
-}
-
 int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
 {
 	netdev_dbg(rmnet_dev, "Setting VND TX queue state to %d\n", enable);
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
index 8a4042f..cae134d 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
@@ -17,7 +17,6 @@
 #define _RMNET_VND_H_
 
 int rmnet_vnd_do_flow_control(struct net_device *dev, int enable);
-struct rmnet_endpoint *rmnet_vnd_get_endpoint(struct net_device *dev);
 int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
 		      struct rmnet_port *port,
 		      struct net_device *real_dev);
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next v2 3/7] net: qualcomm: rmnet: Move rmnet_mode to rmnet_port
From: Subash Abhinov Kasiviswanathan @ 2017-10-12  0:43 UTC (permalink / raw)
  To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1507769038-30231-1-git-send-email-subashab@codeaurora.org>

Mode information on the real device makes it easier to route packets
to rmnet device or bridged device based on the configuration.

Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c   | 12 +++++-------
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h   |  2 +-
 drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c |  3 +--
 3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 8403eea..85fce9c 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -124,20 +124,17 @@ static int rmnet_register_real_device(struct net_device *real_dev)
 }
 
 static void rmnet_set_endpoint_config(struct net_device *dev,
-				      u8 mux_id, u8 rmnet_mode,
-				      struct net_device *egress_dev)
+				      u8 mux_id, struct net_device *egress_dev)
 {
 	struct rmnet_endpoint *ep;
 
-	netdev_dbg(dev, "id %d mode %d dev %s\n",
-		   mux_id, rmnet_mode, egress_dev->name);
+	netdev_dbg(dev, "id %d dev %s\n", mux_id, egress_dev->name);
 
 	ep = rmnet_get_endpoint(dev, mux_id);
 	/* This config is cleared on every set, so its ok to not
 	 * clear it on a device delete.
 	 */
 	memset(ep, 0, sizeof(struct rmnet_endpoint));
-	ep->rmnet_mode = rmnet_mode;
 	ep->egress_dev = egress_dev;
 	ep->mux_id = mux_id;
 }
@@ -183,9 +180,10 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 		   ingress_format, egress_format);
 	port->egress_data_format = egress_format;
 	port->ingress_data_format = ingress_format;
+	port->rmnet_mode = mode;
 
-	rmnet_set_endpoint_config(real_dev, mux_id, mode, dev);
-	rmnet_set_endpoint_config(dev, mux_id, mode, real_dev);
+	rmnet_set_endpoint_config(real_dev, mux_id, dev);
+	rmnet_set_endpoint_config(dev, mux_id, real_dev);
 	return 0;
 
 err2:
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index 0b0c5a7..03d473f 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -24,7 +24,6 @@
  * Exact usage of this parameter depends on the rmnet_mode.
  */
 struct rmnet_endpoint {
-	u8 rmnet_mode;
 	u8 mux_id;
 	struct net_device *egress_dev;
 };
@@ -39,6 +38,7 @@ struct rmnet_port {
 	u32 egress_data_format;
 	struct net_device *rmnet_devices[RMNET_MAX_LOGICAL_EP];
 	u8 nr_rmnet_devs;
+	u8 rmnet_mode;
 };
 
 extern struct rtnl_link_ops rmnet_link_ops;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index b50f401..86e37cc 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -205,8 +205,7 @@ void rmnet_egress_handler(struct sk_buff *skb,
 		}
 	}
 
-	if (ep->rmnet_mode == RMNET_EPMODE_VND)
-		rmnet_vnd_tx_fixup(skb, orig_dev);
+	rmnet_vnd_tx_fixup(skb, orig_dev);
 
 	dev_queue_xmit(skb);
 }
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next v2 2/7] net: qualcomm: rmnet: Remove some unused defines
From: Subash Abhinov Kasiviswanathan @ 2017-10-12  0:43 UTC (permalink / raw)
  To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1507769038-30231-1-git-send-email-subashab@codeaurora.org>

Most of these constants were used in the initial patchset where
custom netlink configuration was used and hence are no longer relevant.

Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
index 7967198..49102f9 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
@@ -19,23 +19,15 @@
 #define RMNET_TX_QUEUE_LEN         1000
 
 /* Constants */
-#define RMNET_EGRESS_FORMAT__RESERVED__         BIT(0)
 #define RMNET_EGRESS_FORMAT_MAP                 BIT(1)
 #define RMNET_EGRESS_FORMAT_AGGREGATION         BIT(2)
 #define RMNET_EGRESS_FORMAT_MUXING              BIT(3)
-#define RMNET_EGRESS_FORMAT_MAP_CKSUMV3         BIT(4)
-#define RMNET_EGRESS_FORMAT_MAP_CKSUMV4         BIT(5)
 
-#define RMNET_INGRESS_FIX_ETHERNET              BIT(0)
 #define RMNET_INGRESS_FORMAT_MAP                BIT(1)
 #define RMNET_INGRESS_FORMAT_DEAGGREGATION      BIT(2)
 #define RMNET_INGRESS_FORMAT_DEMUXING           BIT(3)
 #define RMNET_INGRESS_FORMAT_MAP_COMMANDS       BIT(4)
-#define RMNET_INGRESS_FORMAT_MAP_CKSUMV3        BIT(5)
-#define RMNET_INGRESS_FORMAT_MAP_CKSUMV4        BIT(6)
 
-/* Pass the frame up the stack with no modifications to skb->dev */
-#define RMNET_EPMODE_NONE (0)
 /* Replace skb->dev to a virtual rmnet device and pass up the stack */
 #define RMNET_EPMODE_VND (1)
 /* Pass the frame directly to another device with dev_queue_xmit() */
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next v2 1/7] net: qualcomm: rmnet: Remove existing logic for bridge mode
From: Subash Abhinov Kasiviswanathan @ 2017-10-12  0:43 UTC (permalink / raw)
  To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan
In-Reply-To: <1507769038-30231-1-git-send-email-subashab@codeaurora.org>

This will be rewritten in the following patches.

Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h |  1 -
 .../net/ethernet/qualcomm/rmnet/rmnet_handlers.c   | 77 +++-------------------
 2 files changed, 9 insertions(+), 69 deletions(-)

diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index dde4e9f..0b0c5a7 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -34,7 +34,6 @@ struct rmnet_endpoint {
  */
 struct rmnet_port {
 	struct net_device *dev;
-	struct rmnet_endpoint local_ep;
 	struct rmnet_endpoint muxed_ep[RMNET_MAX_LOGICAL_EP];
 	u32 ingress_data_format;
 	u32 egress_data_format;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
index 540c762..b50f401 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
@@ -44,56 +44,18 @@ static void rmnet_set_skb_proto(struct sk_buff *skb)
 /* Generic handler */
 
 static rx_handler_result_t
-rmnet_bridge_handler(struct sk_buff *skb, struct rmnet_endpoint *ep)
+rmnet_deliver_skb(struct sk_buff *skb)
 {
-	if (!ep->egress_dev)
-		kfree_skb(skb);
-	else
-		rmnet_egress_handler(skb, ep);
+	skb_reset_transport_header(skb);
+	skb_reset_network_header(skb);
+	rmnet_vnd_rx_fixup(skb, skb->dev);
 
+	skb->pkt_type = PACKET_HOST;
+	skb_set_mac_header(skb, 0);
+	netif_receive_skb(skb);
 	return RX_HANDLER_CONSUMED;
 }
 
-static rx_handler_result_t
-rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_endpoint *ep)
-{
-	switch (ep->rmnet_mode) {
-	case RMNET_EPMODE_NONE:
-		return RX_HANDLER_PASS;
-
-	case RMNET_EPMODE_BRIDGE:
-		return rmnet_bridge_handler(skb, ep);
-
-	case RMNET_EPMODE_VND:
-		skb_reset_transport_header(skb);
-		skb_reset_network_header(skb);
-		rmnet_vnd_rx_fixup(skb, skb->dev);
-
-		skb->pkt_type = PACKET_HOST;
-		skb_set_mac_header(skb, 0);
-		netif_receive_skb(skb);
-		return RX_HANDLER_CONSUMED;
-
-	default:
-		kfree_skb(skb);
-		return RX_HANDLER_CONSUMED;
-	}
-}
-
-static rx_handler_result_t
-rmnet_ingress_deliver_packet(struct sk_buff *skb,
-			     struct rmnet_port *port)
-{
-	if (!port) {
-		kfree_skb(skb);
-		return RX_HANDLER_CONSUMED;
-	}
-
-	skb->dev = port->local_ep.egress_dev;
-
-	return rmnet_deliver_skb(skb, &port->local_ep);
-}
-
 /* MAP handler */
 
 static rx_handler_result_t
@@ -130,7 +92,7 @@ static void rmnet_set_skb_proto(struct sk_buff *skb)
 	skb_pull(skb, sizeof(struct rmnet_map_header));
 	skb_trim(skb, len);
 	rmnet_set_skb_proto(skb);
-	return rmnet_deliver_skb(skb, ep);
+	return rmnet_deliver_skb(skb);
 }
 
 static rx_handler_result_t
@@ -204,29 +166,8 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
 	dev = skb->dev;
 	port = rmnet_get_port(dev);
 
-	if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP) {
+	if (port->ingress_data_format & RMNET_INGRESS_FORMAT_MAP)
 		rc = rmnet_map_ingress_handler(skb, port);
-	} else {
-		switch (ntohs(skb->protocol)) {
-		case ETH_P_MAP:
-			if (port->local_ep.rmnet_mode ==
-				RMNET_EPMODE_BRIDGE) {
-				rc = rmnet_ingress_deliver_packet(skb, port);
-			} else {
-				kfree_skb(skb);
-				rc = RX_HANDLER_CONSUMED;
-			}
-			break;
-
-		case ETH_P_IP:
-		case ETH_P_IPV6:
-			rc = rmnet_ingress_deliver_packet(skb, port);
-			break;
-
-		default:
-			rc = RX_HANDLER_PASS;
-		}
-	}
 
 	return rc;
 }
-- 
1.9.1

^ permalink raw reply related

* [PATCH net-next v2 0/7] net: qualcomm: rmnet: Rewrite some existing functionality
From: Subash Abhinov Kasiviswanathan @ 2017-10-12  0:43 UTC (permalink / raw)
  To: davem, netdev; +Cc: Subash Abhinov Kasiviswanathan

This series fixes some of the broken rmnet functionality.
Bridge mode is re-written and made useable and the muxed_ep is converted to hlist.

Patches 1-5 are cleanups in preparation for these changes.
Patch 6 does the hlist conversion.
Patch 7 has the implementation of the rmnet bridge mode.

v1->v2: Fix the warning and code style issue in rmnet_rx_handler as
mentioned by David.

Subash Abhinov Kasiviswanathan (7):
  net: qualcomm: rmnet: Remove existing logic for bridge mode
  net: qualcomm: rmnet: Remove some unused defines
  net: qualcomm: rmnet: Move rmnet_mode to rmnet_port
  net: qualcomm: rmnet: Remove duplicate setting of rmnet private info
  net: qualcomm: rmnet: Remove duplicate setting of rmnet_devices
  net: qualcomm: rmnet: Convert the muxed endpoint to hlist
  net: qualcomm: rmnet: Implement bridge mode

 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c | 166 ++++++++++++++++-----
 drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h |  19 +--
 .../net/ethernet/qualcomm/rmnet/rmnet_handlers.c   | 137 +++++++----------
 .../net/ethernet/qualcomm/rmnet/rmnet_handlers.h   |   3 +-
 .../ethernet/qualcomm/rmnet/rmnet_map_command.c    |   4 +-
 .../net/ethernet/qualcomm/rmnet/rmnet_private.h    |   8 -
 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c    |  36 ++---
 drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h    |   7 +-
 8 files changed, 207 insertions(+), 173 deletions(-)

-- 
1.9.1

^ permalink raw reply

* Re: [PATCH net-next 2/4] security: bpf: Add LSM hooks for bpf object related syscall
From: James Morris @ 2017-10-12  0:31 UTC (permalink / raw)
  To: Chenbo Feng
  Cc: netdev, SELinux, linux-security-module, Jeffrey Vander Stoep,
	Lorenzo Colitti, Alexei Starovoitov, Daniel Borkmann, Chenbo Feng
In-Reply-To: <20171004182932.140028-3-chenbofeng.kernel@gmail.com>

On Wed, 4 Oct 2017, Chenbo Feng wrote:

>  int bpf_map_new_fd(struct bpf_map *map, int flags)
>  {
> +	if (security_bpf_map(map, OPEN_FMODE(flags)))
> +		return -EPERM;
> +

Don't hardcode -EPERM here, return the actual error from 
security_bpf_map().

> +	if (security_bpf_prog(prog))
> +		return -EPERM;
> +

Same.

> +	err = security_bpf(cmd, &attr, size);
> +	if (err)
> +		return -EPERM;

Same.


- James


^ permalink raw reply

* Re: BUG:af_packet fails to TX TSO frames
From: Willem de Bruijn @ 2017-10-12  0:19 UTC (permalink / raw)
  To: Anton Ivanov; +Cc: Anton Ivanov, Network Development, David Miller
In-Reply-To: <40e87e75-742f-3542-b79e-1e7fee9b4485@cambridgegreys.com>

On Wed, Oct 11, 2017 at 6:01 PM, Anton Ivanov
<anton.ivanov@cambridgegreys.com> wrote:
> [snip]
>
>> This will be tomorrow though, it is late here.
>>
>> The only obvious difference I can see at this point is that I am using
>> iovs and sending the vnet header as iov[0] and the data in pieces after
>> that while your code is doing a send() for the whole frame. This should
>> not make any difference though - it all ends up as an iov internally in
>> the kernel.
>
> Spoke too soon. It is not reporting any errors, but there is nothing
> coming out on the actual Ethernet.

It works for me on various platforms. On the receiver, drop these fake
tcp packets in iptables and read them with tcpdump

   iptables -A PREROUTING -t raw -p tcp --dport 9 -j DROP
   tcpdump src $src_ip

Note that not all combinations of flags are supported by the kernel
and that some flags have non-obvious behavior (disable a feature, in
place of enable it).

Specifically, mtu sized packets either must not pass a vnet_hdr or
must pass one with gso explicitly disabled ('-G').

  psock_txring_vnet -s $src_ip $dst_ip -l 1400
  psock_txring_vnet -s $src_ip $dst_ip -l 1400 -v -G
  psock_txring_vnet -s $src_ip $dst_ip -l 1400 -N
  psock_txring_vnet -s $src_ip $dst_ip -l 1400 -N -v -G

Conversely, packets that exceed mtu have to have the gso flags in the
virtio_net_hdr:

  psock_txring_vnet -s $src_ip $dst_ip -l 4400 -v
  psock_txring_vnet -s $src_ip $dst_ip -l 4400 -N -v

When sending a large packet, but not passing a virtio_net_hdr along
('-v'), the test fails with

  psock_txring_vnet: send: Message too long

When passing a header along, but not disabling gso, the packet is
indeed dropped silently.

I verified correct segmentation with three modes of ethtool

  ethtool -K eth0 tso off gso off
  ethtool -K eth0 tso off gso on
  ethtool -K eth0 tso on gso on

by reading tcpdump on the sender.

The receive side results are the same with dev_queue_xmit and
packet_direct_xmit ('-q') mode. With direct_xmit, the packets are not
observed on the send side.

^ permalink raw reply

* [PATCH next] ipvlan: always use the current L2 addr of the master
From: Mahesh Bandewar @ 2017-10-12  0:16 UTC (permalink / raw)
  To: Netdev; +Cc: Eric Dumazet, David Miller, Mahesh Bandewar, Mahesh Bandewar

From: Mahesh Bandewar <maheshb@google.com>

If the underlying master ever changes its L2 (e.g. bonding device),
then make sure that the IPvlan slaves always emit packets with the
current L2 of the master instead of the stale mac addr which was
copied during the device creation. The problem can be seen with
following script -

  #!/bin/bash
  # Create a vEth pair
  ip link add dev veth0 type veth peer name veth1
  ip link set veth0 up
  ip link set veth1 up
  ip link show veth0
  ip link show veth1
  # Create an IPvlan device on one end of this vEth pair.
  ip link add link veth0 dev ipvl0 type ipvlan mode l2
  ip link show ipvl0
  # Change the mac-address of the vEth master.
  ip link set veth0 address 02:11:22:33:44:55

Fixes: 2ad7bf363841 ("ipvlan: Initial check-in of the IPVLAN driver.")
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
 drivers/net/ipvlan/ipvlan_main.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index c74893c1e620..5832091680f4 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -407,7 +407,7 @@ static int ipvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
 	 * while the packets use the mac-addr on the physical device.
 	 */
 	return dev_hard_header(skb, phy_dev, type, daddr,
-			       saddr ? : dev->dev_addr, len);
+			       saddr ? : phy_dev->dev_addr, len);
 }
 
 static const struct header_ops ipvlan_header_ops = {
@@ -730,6 +730,11 @@ static int ipvlan_device_event(struct notifier_block *unused,
 			ipvlan_adjust_mtu(ipvlan, dev);
 		break;
 
+	case NETDEV_CHANGEADDR:
+		list_for_each_entry(ipvlan, &port->ipvlans, pnode)
+			ether_addr_copy(ipvlan->dev->dev_addr, dev->dev_addr);
+		break;
+
 	case NETDEV_PRE_TYPE_CHANGE:
 		/* Forbid underlying device to change its type. */
 		return NOTIFY_BAD;
-- 
2.15.0.rc0.271.g36b669edcc-goog

^ permalink raw reply related

* Re: [Intel-wired-lan] [jkirsher/next-queue PATCH v4 6/6] i40e: Enable cloud filters via tc-flower
From: Shannon Nelson @ 2017-10-11 23:30 UTC (permalink / raw)
  To: intel-wired-lan, Amritha Nambiar; +Cc: netdev@vger.kernel.org
In-Reply-To: <150768148418.5320.6338243543224569414.stgit@anamdev.jf.intel.com>

On 10/10/2017 5:24 PM, Amritha Nambiar wrote:
> This patch enables tc-flower based hardware offloads. tc flower
> filter provided by the kernel is configured as driver specific
> cloud filter. The patch implements functions and admin queue
> commands needed to support cloud filters in the driver and
> adds cloud filters to configure these tc-flower filters.
> 
> The classification function of the filter is to direct matched
> packets to a traffic class which is set based on the offloaded
> tc-flower classid. The approach here is similar to the tc 'prio'
> qdisc which uses the classid for band selection. The ingress qdisc
> is called ffff:0, so traffic classes are ffff:1 to ffff:8 (i40e
> has max of 8 TCs). TC0 is minor number 1, TC1 is minor number 2 etc.
> 
> # tc qdisc add dev eth0 ingress
> # ethtool -K eth0 hw-tc-offload on
> 
> Match Dst MAC and route to TC0:
> # tc filter add dev eth0 protocol ip parent ffff:\
>    prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw\
>    classid ffff:1
> 
> Match Dst IPv4,Dst Port and route to TC1:
> # tc filter add dev eth0 protocol ip parent ffff:\
>    prio 2 flower dst_ip 192.168.3.5/32\
>    ip_proto udp dst_port 25 skip_sw\
>    classid ffff:2
> 
> Match Dst IPv6,Dst Port and route to TC1:
> # tc filter add dev eth0 protocol ipv6 parent ffff:\
>    prio 3 flower dst_ip fe8::200:1\
>    ip_proto udp dst_port 66 skip_sw\
>    classid ffff:2
> 
> Delete tc flower filter:
> Example:
> 
> # tc filter del dev eth0 parent ffff: prio 3 handle 0x1 flower
> # tc filter del dev eth0 parent ffff:
> 
> Flow Director Sideband is disabled while configuring cloud filters
> via tc-flower and until any cloud filter exists.
> 
> Unsupported matches when cloud filters are added using enhanced
> big buffer cloud filter mode of underlying switch include:
> 1. source port and source IP
> 2. Combined MAC address and IP fields.
> 3. Not specifying L4 port
> 
> These filter matches can however be used to redirect traffic to
> the main VSI (tc 0) which does not require the enhanced big buffer
> cloud filter support.
> 
> v4: Use classid to set traffic class for matched packets. Do not
> allow disabling hw-tc-offloads when offloaded tc filters are active.
> v3: Cleaned up some lengthy function names. Changed ipv6 address to
> __be32 array instead of u8 array. Used macro for IP version. Minor
> formatting changes.
> v2:
> 1. Moved I40E_SWITCH_MODE_MASK definition to i40e_type.h
> 2. Moved dev_info for add/deleting cloud filters in else condition
> 3. Fixed some format specifier in dev_err logs
> 4. Refactored i40e_get_capabilities to take an additional
>     list_type parameter and use it to query device and function
>     level capabilities.
> 5. Fixed parsing tc redirect action to check for the is_tcf_mirred_tc()
>     to verify if redirect to a traffic class is supported.
> 6. Added comments for Geneve fix in cloud filter big buffer AQ
>     function definitions.
> 7. Cleaned up setup_tc interface to rebase and work with Jiri's
>     updates, separate function to process tc cls flower offloads.
> 8. Changes to make Flow Director Sideband and Cloud filters mutually
>     exclusive.
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Signed-off-by: Kiran Patil <kiran.patil@intel.com>
> Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>
> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
> ---
>   drivers/net/ethernet/intel/i40e/i40e.h             |   45 +
>   drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |    3
>   drivers/net/ethernet/intel/i40e/i40e_common.c      |  189 ++++
>   drivers/net/ethernet/intel/i40e/i40e_main.c        |  913 +++++++++++++++++++-
>   drivers/net/ethernet/intel/i40e/i40e_prototype.h   |   16
>   drivers/net/ethernet/intel/i40e/i40e_type.h        |    1
>   .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |    3
>   7 files changed, 1140 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
> index b938bb4a..c3f1312 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e.h
> @@ -55,6 +55,8 @@
>   #include <linux/net_tstamp.h>
>   #include <linux/ptp_clock_kernel.h>
>   #include <net/pkt_cls.h>
> +#include <net/tc_act/tc_gact.h>
> +#include <net/tc_act/tc_mirred.h>
>   #include "i40e_type.h"
>   #include "i40e_prototype.h"
>   #include "i40e_client.h"
> @@ -253,9 +255,48 @@ struct i40e_fdir_filter {
>   	u32 fd_id;
>   };
>   
> +#define IPV4_VERSION 4
> +#define IPV6_VERSION 6

Why bother with yet-another-ip-type name?  Just use the existing 
ETH_P_IP and ETH_P_IPV6.

> +
> +#define I40E_CLOUD_FIELD_OMAC	0x01
> +#define I40E_CLOUD_FIELD_IMAC	0x02
> +#define I40E_CLOUD_FIELD_IVLAN	0x04
> +#define I40E_CLOUD_FIELD_TEN_ID	0x08
> +#define I40E_CLOUD_FIELD_IIP	0x10
> +
> +#define I40E_CLOUD_FILTER_FLAGS_OMAC	I40E_CLOUD_FIELD_OMAC
> +#define I40E_CLOUD_FILTER_FLAGS_IMAC	I40E_CLOUD_FIELD_IMAC
> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN	(I40E_CLOUD_FIELD_IMAC | \
> +						 I40E_CLOUD_FIELD_IVLAN)
> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID	(I40E_CLOUD_FIELD_IMAC | \
> +						 I40E_CLOUD_FIELD_TEN_ID)
> +#define I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC (I40E_CLOUD_FIELD_OMAC | \
> +						  I40E_CLOUD_FIELD_IMAC | \
> +						  I40E_CLOUD_FIELD_TEN_ID)
> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID (I40E_CLOUD_FIELD_IMAC | \
> +						   I40E_CLOUD_FIELD_IVLAN | \
> +						   I40E_CLOUD_FIELD_TEN_ID)
> +#define I40E_CLOUD_FILTER_FLAGS_IIP	I40E_CLOUD_FIELD_IIP
> +
>   struct i40e_cloud_filter {
>   	struct hlist_node cloud_node;
>   	unsigned long cookie;
> +	/* cloud filter input set follows */
> +	u8 dst_mac[ETH_ALEN];
> +	u8 src_mac[ETH_ALEN];
> +	__be16 vlan_id;
> +	__be32 dst_ip;
> +	__be32 src_ip;
> +	__be32 dst_ipv6[4];
> +	__be32 src_ipv6[4];

You could save a little space by making these unions as done in struct 
i40e_aqc_add_remove_cloud_filters_element_data, especially since that's 
what you're putting this data into.  You might also use the existing 
type definitions
	struct in6_addr
	struct in_addr


> +	__be16 dst_port;
> +	__be16 src_port;
> +	u32 ip_version;
> +	u8 ip_proto;	/* IPPROTO value */

You might want to re-order these to pack them better and not end up with 
so much padding space in the struct.

> +	u32 tenant_id;
> +	u8 flags;
> +#define I40E_CLOUD_TNL_TYPE_NONE	0xff
> +	u8 tunnel_type;
>   	u16 seid;	/* filter control */
>   };
>   
> @@ -492,6 +533,8 @@ struct i40e_pf {
>   #define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED	BIT(27)
>   #define I40E_FLAG_SOURCE_PRUNING_DISABLED	BIT(28)
>   #define I40E_FLAG_TC_MQPRIO			BIT(29)
> +#define I40E_FLAG_FD_SB_INACTIVE		BIT(30)
> +#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER		BIT(31)
>   
>   	struct i40e_client_instance *cinst;
>   	bool stat_offsets_loaded;
> @@ -574,6 +617,8 @@ struct i40e_pf {
>   	u16 phy_led_val;
>   
>   	u16 override_q_count;
> +	u16 last_sw_conf_flags;
> +	u16 last_sw_conf_valid_flags;
>   };
>   
>   /**
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> index bcc7986..06c534c 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> @@ -1392,6 +1392,9 @@ struct i40e_aqc_cloud_filters_element_data {
>   		struct {
>   			u8 data[16];
>   		} v6;
> +		struct {
> +			__le16 data[8];
> +		} raw_v6;
>   	} ipaddr;
>   	__le16	flags;
>   #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT			0
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
> index 0b3c5b7..257b0c8 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
> @@ -5431,5 +5431,194 @@ i40e_add_pinfo_to_list(struct i40e_hw *hw,
>   
>   	status = i40e_aq_write_ppp(hw, (void *)sec, sec->data_end,
>   				   track_id, &offset, &info, NULL);
> +
> +	return status;
> +}
> +
> +/**
> + * i40e_aq_add_cloud_filters
> + * @hw: pointer to the hardware structure
> + * @seid: VSI seid to add cloud filters from
> + * @filters: Buffer which contains the filters to be added
> + * @filter_count: number of filters contained in the buffer
> + *
> + * Set the cloud filters for a given VSI.  The contents of the
> + * i40e_aqc_cloud_filters_element_data are filled in by the caller
> + * of the function.
> + *
> + **/
> +enum i40e_status_code
> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 seid,
> +			  struct i40e_aqc_cloud_filters_element_data *filters,
> +			  u8 filter_count)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_add_remove_cloud_filters *cmd =
> +	(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;
> +	enum i40e_status_code status;
> +	u16 buff_len;
> +
> +	i40e_fill_default_direct_cmd_desc(&desc,
> +					  i40e_aqc_opc_add_cloud_filters);
> +
> +	buff_len = filter_count * sizeof(*filters);
> +	desc.datalen = cpu_to_le16(buff_len);
> +	desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
> +	cmd->num_filters = filter_count;
> +	cmd->seid = cpu_to_le16(seid);
> +
> +	status = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);
> +
> +	return status;
> +}
> +
> +/**
> + * i40e_aq_add_cloud_filters_bb
> + * @hw: pointer to the hardware structure
> + * @seid: VSI seid to add cloud filters from
> + * @filters: Buffer which contains the filters in big buffer to be added
> + * @filter_count: number of filters contained in the buffer
> + *
> + * Set the big buffer cloud filters for a given VSI.  The contents of the
> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the
> + * function.
> + *
> + **/
> +i40e_status
> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
> +			     struct i40e_aqc_cloud_filters_element_bb *filters,
> +			     u8 filter_count)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_add_remove_cloud_filters *cmd =
> +	(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;
> +	i40e_status status;
> +	u16 buff_len;
> +	int i;
> +
> +	i40e_fill_default_direct_cmd_desc(&desc,
> +					  i40e_aqc_opc_add_cloud_filters);
> +
> +	buff_len = filter_count * sizeof(*filters);
> +	desc.datalen = cpu_to_le16(buff_len);
> +	desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
> +	cmd->num_filters = filter_count;
> +	cmd->seid = cpu_to_le16(seid);
> +	cmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;
> +
> +	for (i = 0; i < filter_count; i++) {
> +		u16 tnl_type;
> +		u32 ti;
> +
> +		tnl_type = (le16_to_cpu(filters[i].element.flags) &
> +			   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>
> +			   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;
> +
> +		/* For Geneve, the VNI should be placed in offset shifted by a
> +		 * byte than the offset for the Tenant ID for rest of the

This comment isn't quite clear - maybe s/than/then/ ?

> +		 * tunnels.
> +		 */
> +		if (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {
> +			ti = le32_to_cpu(filters[i].element.tenant_id);
> +			filters[i].element.tenant_id = cpu_to_le32(ti << 8);
> +		}
> +	}
> +
> +	status = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);
> +
> +	return status;
> +}
> +
> +/**
> + * i40e_aq_rem_cloud_filters
> + * @hw: pointer to the hardware structure
> + * @seid: VSI seid to remove cloud filters from
> + * @filters: Buffer which contains the filters to be removed
> + * @filter_count: number of filters contained in the buffer
> + *
> + * Remove the cloud filters for a given VSI.  The contents of the
> + * i40e_aqc_cloud_filters_element_data are filled in by the caller
> + * of the function.
> + *
> + **/
> +enum i40e_status_code
> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 seid,
> +			  struct i40e_aqc_cloud_filters_element_data *filters,
> +			  u8 filter_count)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_add_remove_cloud_filters *cmd =
> +	(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;
> +	enum i40e_status_code status;
> +	u16 buff_len;
> +
> +	i40e_fill_default_direct_cmd_desc(&desc,
> +					  i40e_aqc_opc_remove_cloud_filters);
> +
> +	buff_len = filter_count * sizeof(*filters);
> +	desc.datalen = cpu_to_le16(buff_len);
> +	desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
> +	cmd->num_filters = filter_count;
> +	cmd->seid = cpu_to_le16(seid);
> +
> +	status = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);
> +
> +	return status;
> +}
> +
> +/**
> + * i40e_aq_rem_cloud_filters_bb
> + * @hw: pointer to the hardware structure
> + * @seid: VSI seid to remove cloud filters from
> + * @filters: Buffer which contains the filters in big buffer to be removed
> + * @filter_count: number of filters contained in the buffer
> + *
> + * Remove the big buffer cloud filters for a given VSI.  The contents of the
> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the
> + * function.
> + *
> + **/
> +i40e_status
> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
> +			     struct i40e_aqc_cloud_filters_element_bb *filters,
> +			     u8 filter_count)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_add_remove_cloud_filters *cmd =
> +	(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;
> +	i40e_status status;
> +	u16 buff_len;
> +	int i;
> +
> +	i40e_fill_default_direct_cmd_desc(&desc,
> +					  i40e_aqc_opc_remove_cloud_filters);
> +
> +	buff_len = filter_count * sizeof(*filters);
> +	desc.datalen = cpu_to_le16(buff_len);
> +	desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
> +	cmd->num_filters = filter_count;
> +	cmd->seid = cpu_to_le16(seid);
> +	cmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;
> +
> +	for (i = 0; i < filter_count; i++) {
> +		u16 tnl_type;
> +		u32 ti;
> +
> +		tnl_type = (le16_to_cpu(filters[i].element.flags) &
> +			   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>
> +			   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;
> +
> +		/* For Geneve, the VNI should be placed in offset shifted by a
> +		 * byte than the offset for the Tenant ID for rest of the

Again, some wording cleanup needed.

> +		 * tunnels.
> +		 */
> +		if (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {
> +			ti = le32_to_cpu(filters[i].element.tenant_id);
> +			filters[i].element.tenant_id = cpu_to_le32(ti << 8);
> +		}
> +	}
> +
> +	status = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);
> +
>   	return status;
>   }
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index bcdb16a..3f3279e 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
> @@ -69,6 +69,15 @@ static int i40e_reset(struct i40e_pf *pf);
>   static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);
>   static void i40e_fdir_sb_setup(struct i40e_pf *pf);
>   static int i40e_veb_get_bw_info(struct i40e_veb *veb);
> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
> +				     struct i40e_cloud_filter *filter,
> +				     bool add);
> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
> +					     struct i40e_cloud_filter *filter,
> +					     bool add);
> +static int i40e_get_capabilities(struct i40e_pf *pf,
> +				 enum i40e_admin_queue_opc list_type);
> +
>   
>   /* i40e_pci_tbl - PCI Device ID Table
>    *
> @@ -5480,7 +5489,11 @@ int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate)
>    **/
>   static void i40e_remove_queue_channels(struct i40e_vsi *vsi)
>   {
> +	enum i40e_admin_queue_err last_aq_status;
> +	struct i40e_cloud_filter *cfilter;
>   	struct i40e_channel *ch, *ch_tmp;
> +	struct i40e_pf *pf = vsi->back;
> +	struct hlist_node *node;
>   	int ret, i;
>   
>   	/* Reset rss size that was stored when reconfiguring rss for
> @@ -5521,6 +5534,29 @@ static void i40e_remove_queue_channels(struct i40e_vsi *vsi)
>   				 "Failed to reset tx rate for ch->seid %u\n",
>   				 ch->seid);
>   
> +		/* delete cloud filters associated with this channel */
> +		hlist_for_each_entry_safe(cfilter, node,
> +					  &pf->cloud_filter_list, cloud_node) {
> +			if (cfilter->seid != ch->seid)
> +				continue;
> +
> +			hash_del(&cfilter->cloud_node);
> +			if (cfilter->dst_port)
> +				ret = i40e_add_del_cloud_filter_big_buf(vsi,
> +									cfilter,
> +									false);
> +			else
> +				ret = i40e_add_del_cloud_filter(vsi, cfilter,
> +								false);
> +			last_aq_status = pf->hw.aq.asq_last_status;
> +			if (ret)
> +				dev_info(&pf->pdev->dev,
> +					 "Failed to delete cloud filter, err %s aq_err %s\n",
> +					 i40e_stat_str(&pf->hw, ret),
> +					 i40e_aq_str(&pf->hw, last_aq_status));
> +			kfree(cfilter);
> +		}
> +
>   		/* delete VSI from FW */
>   		ret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,
>   					     NULL);
> @@ -5972,6 +6008,63 @@ static bool i40e_setup_channel(struct i40e_pf *pf, struct i40e_vsi *vsi,
>   }
>   
>   /**
> + * i40e_validate_and_set_switch_mode - sets up switch mode correctly
> + * @vsi: ptr to VSI which has PF backing
> + *
> + * Sets up switch mode correctly if it needs to be changed and perform
> + * what are allowed modes.
> + **/
> +static int i40e_validate_and_set_switch_mode(struct i40e_vsi *vsi)
> +{
> +	u8 mode;
> +	struct i40e_pf *pf = vsi->back;
> +	struct i40e_hw *hw = &pf->hw;
> +	int ret;
> +
> +	ret = i40e_get_capabilities(pf, i40e_aqc_opc_list_dev_capabilities);
> +	if (ret)
> +		return -EINVAL;
> +
> +	if (hw->dev_caps.switch_mode) {
> +		/* if switch mode is set, support mode2 (non-tunneled for
> +		 * cloud filter) for now
> +		 */
> +		u32 switch_mode = hw->dev_caps.switch_mode &
> +							I40E_SWITCH_MODE_MASK;
> +		if (switch_mode >= I40E_NVM_IMAGE_TYPE_MODE1) {
> +			if (switch_mode == I40E_NVM_IMAGE_TYPE_MODE2)
> +				return 0;
> +			dev_err(&pf->pdev->dev,
> +				"Invalid switch_mode (%d), only non-tunneled mode for cloud filter is supported\n",
> +				hw->dev_caps.switch_mode);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	/* Set Bit 7 to be valid */
> +	mode = I40E_AQ_SET_SWITCH_BIT7_VALID;
> +
> +	/* Set L4type to both TCP and UDP support */
> +	mode |= I40E_AQ_SET_SWITCH_L4_TYPE_BOTH;
> +
> +	/* Set cloud filter mode */
> +	mode |= I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL;
> +
> +	/* Prep mode field for set_switch_config */
> +	ret = i40e_aq_set_switch_config(hw, pf->last_sw_conf_flags,
> +					pf->last_sw_conf_valid_flags,
> +					mode, NULL);
> +	if (ret && hw->aq.asq_last_status != I40E_AQ_RC_ESRCH)
> +		dev_err(&pf->pdev->dev,
> +			"couldn't set switch config bits, err %s aq_err %s\n",
> +			i40e_stat_str(hw, ret),
> +			i40e_aq_str(hw,
> +				    hw->aq.asq_last_status));
> +
> +	return ret;
> +}
> +
> +/**
>    * i40e_create_queue_channel - function to create channel
>    * @vsi: VSI to be configured
>    * @ch: ptr to channel (it contains channel specific params)
> @@ -6750,13 +6843,673 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data)
>   	return ret;
>   }
>   
> +/**
> + * i40e_set_cld_element - sets cloud filter element data
> + * @filter: cloud filter rule
> + * @cld: ptr to cloud filter element data
> + *
> + * This is helper function to copy data into cloud filter element
> + **/
> +static inline void
> +i40e_set_cld_element(struct i40e_cloud_filter *filter,
> +		     struct i40e_aqc_cloud_filters_element_data *cld)
> +{
> +	int i, j;
> +	u32 ipa;
> +
> +	memset(cld, 0, sizeof(*cld));
> +	ether_addr_copy(cld->outer_mac, filter->dst_mac);
> +	ether_addr_copy(cld->inner_mac, filter->src_mac);
> +
> +	if (filter->ip_version == IPV6_VERSION) {
> +#define IPV6_MAX_INDEX	(ARRAY_SIZE(filter->dst_ipv6) - 1)
> +		for (i = 0, j = 0; i < 4; i++, j += 2) {

s/4/ARRAY_SIZE(filter->dst_ipv6)/

> +			ipa = be32_to_cpu(filter->dst_ipv6[IPV6_MAX_INDEX - i]);
> +			ipa = cpu_to_le32(ipa);
> +			memcpy(&cld->ipaddr.raw_v6.data[j], &ipa, 4);

s/4/sizeof(ipa)/

> +		}
> +	} else {
> +		ipa = be32_to_cpu(filter->dst_ip);
> +		memcpy(&cld->ipaddr.v4.data, &ipa, 4);

s/4/sizeof(ipa)/

> +	}
> +
> +	cld->inner_vlan = cpu_to_le16(ntohs(filter->vlan_id));
> +
> +	/* tenant_id is not supported by FW now, once the support is enabled
> +	 * fill the cld->tenant_id with cpu_to_le32(filter->tenant_id)
> +	 */
> +	if (filter->tenant_id)
> +		return;
> +}
> +
> +/**
> + * i40e_add_del_cloud_filter - Add/del cloud filter
> + * @vsi: pointer to VSI
> + * @filter: cloud filter rule
> + * @add: if true, add, if false, delete
> + *
> + * Add or delete a cloud filter for a specific flow spec.
> + * Returns 0 if the filter were successfully added.
> + **/
> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
> +				     struct i40e_cloud_filter *filter, bool add)
> +{
> +	struct i40e_aqc_cloud_filters_element_data cld_filter;
> +	struct i40e_pf *pf = vsi->back;
> +	int ret;
> +	static const u16 flag_table[128] = {
> +		[I40E_CLOUD_FILTER_FLAGS_OMAC]  =
> +			I40E_AQC_ADD_CLOUD_FILTER_OMAC,
> +		[I40E_CLOUD_FILTER_FLAGS_IMAC]  =
> +			I40E_AQC_ADD_CLOUD_FILTER_IMAC,
> +		[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN]  =
> +			I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN,
> +		[I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID] =
> +			I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID,
> +		[I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC] =
> +			I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC,
> +		[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID] =
> +			I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID,
> +		[I40E_CLOUD_FILTER_FLAGS_IIP] =
> +			I40E_AQC_ADD_CLOUD_FILTER_IIP,
> +	};
> +
> +	if (filter->flags >= ARRAY_SIZE(flag_table))
> +		return I40E_ERR_CONFIG;
> +
> +	/* copy element needed to add cloud filter from filter */
> +	i40e_set_cld_element(filter, &cld_filter);
> +
> +	if (filter->tunnel_type != I40E_CLOUD_TNL_TYPE_NONE)
> +		cld_filter.flags = cpu_to_le16(filter->tunnel_type <<
> +					     I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);
> +
> +	if (filter->ip_version == IPV6_VERSION)
> +		cld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |
> +						I40E_AQC_ADD_CLOUD_FLAGS_IPV6);
> +	else
> +		cld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |
> +						I40E_AQC_ADD_CLOUD_FLAGS_IPV4);
> +
> +	if (add)
> +		ret = i40e_aq_add_cloud_filters(&pf->hw, filter->seid,
> +						&cld_filter, 1);
> +	else
> +		ret = i40e_aq_rem_cloud_filters(&pf->hw, filter->seid,
> +						&cld_filter, 1);
> +	if (ret)
> +		dev_dbg(&pf->pdev->dev,
> +			"Failed to %s cloud filter using l4 port %u, err %d aq_err %d\n",
> +			add ? "add" : "delete", filter->dst_port, ret,
> +			pf->hw.aq.asq_last_status);
> +	else
> +		dev_info(&pf->pdev->dev,
> +			 "%s cloud filter for VSI: %d\n",
> +			 add ? "Added" : "Deleted", filter->seid);
> +	return ret;
> +}
> +
> +/**
> + * i40e_add_del_cloud_filter_big_buf - Add/del cloud filter using big_buf
> + * @vsi: pointer to VSI
> + * @filter: cloud filter rule
> + * @add: if true, add, if false, delete
> + *
> + * Add or delete a cloud filter for a specific flow spec using big buffer.
> + * Returns 0 if the filter were successfully added.
> + **/
> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
> +					     struct i40e_cloud_filter *filter,
> +					     bool add)
> +{
> +	struct i40e_aqc_cloud_filters_element_bb cld_filter;
> +	struct i40e_pf *pf = vsi->back;
> +	int ret;
> +
> +	/* Both (src/dst) valid mac_addr are not supported */
> +	if ((is_valid_ether_addr(filter->dst_mac) &&
> +	     is_valid_ether_addr(filter->src_mac)) ||
> +	    (is_multicast_ether_addr(filter->dst_mac) &&
> +	     is_multicast_ether_addr(filter->src_mac)))
> +		return -EINVAL;
> +
> +	/* Make sure port is specified, otherwise bail out, for channel
> +	 * specific cloud filter needs 'L4 port' to be non-zero
> +	 */
> +	if (!filter->dst_port)
> +		return -EINVAL;
> +
> +	/* adding filter using src_port/src_ip is not supported at this stage */
> +	if (filter->src_port || filter->src_ip ||
> +	    !ipv6_addr_any((struct in6_addr *)&filter->src_ipv6))
> +		return -EINVAL;

Another good reason to use the existing definitions in your new struct

> +
> +	/* copy element needed to add cloud filter from filter */
> +	i40e_set_cld_element(filter, &cld_filter.element);
> +
> +	if (is_valid_ether_addr(filter->dst_mac) ||
> +	    is_valid_ether_addr(filter->src_mac) ||
> +	    is_multicast_ether_addr(filter->dst_mac) ||
> +	    is_multicast_ether_addr(filter->src_mac)) {
> +		/* MAC + IP : unsupported mode */
> +		if (filter->dst_ip)
> +			return -EINVAL;
> +
> +		/* since we validated that L4 port must be valid before
> +		 * we get here, start with respective "flags" value
> +		 * and update if vlan is present or not
> +		 */
> +		cld_filter.element.flags =
> +			cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT);
> +
> +		if (filter->vlan_id) {
> +			cld_filter.element.flags =
> +			cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);
> +		}
> +
> +	} else if (filter->dst_ip || filter->ip_version == IPV6_VERSION) {
> +		cld_filter.element.flags =
> +				cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT);
> +		if (filter->ip_version == IPV6_VERSION)
> +			cld_filter.element.flags |=
> +				cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV6);
> +		else
> +			cld_filter.element.flags |=
> +				cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV4);
> +	} else {
> +		dev_err(&pf->pdev->dev,
> +			"either mac or ip has to be valid for cloud filter\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Now copy L4 port in Byte 6..7 in general fields */
> +	cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0] =
> +						be16_to_cpu(filter->dst_port);
> +
> +	if (add) {
> +		/* Validate current device switch mode, change if necessary */
> +		ret = i40e_validate_and_set_switch_mode(vsi);
> +		if (ret) {
> +			dev_err(&pf->pdev->dev,
> +				"failed to set switch mode, ret %d\n",
> +				ret);
> +			return ret;
> +		}
> +
> +		ret = i40e_aq_add_cloud_filters_bb(&pf->hw, filter->seid,
> +						   &cld_filter, 1);
> +	} else {
> +		ret = i40e_aq_rem_cloud_filters_bb(&pf->hw, filter->seid,
> +						   &cld_filter, 1);
> +	}
> +
> +	if (ret)
> +		dev_dbg(&pf->pdev->dev,
> +			"Failed to %s cloud filter(big buffer) err %d aq_err %d\n",
> +			add ? "add" : "delete", ret, pf->hw.aq.asq_last_status);
> +	else
> +		dev_info(&pf->pdev->dev,
> +			 "%s cloud filter for VSI: %d, L4 port: %d\n",
> +			 add ? "add" : "delete", filter->seid,
> +			 ntohs(filter->dst_port));
> +	return ret;
> +}
> +
> +/**
> + * i40e_parse_cls_flower - Parse tc flower filters provided by kernel
> + * @vsi: Pointer to VSI
> + * @cls_flower: Pointer to struct tc_cls_flower_offload
> + * @filter: Pointer to cloud filter structure
> + *
> + **/
> +static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
> +				 struct tc_cls_flower_offload *f,
> +				 struct i40e_cloud_filter *filter)
> +{
> +	struct i40e_pf *pf = vsi->back;
> +	u16 addr_type = 0;
> +	u8 field_flags = 0;
> +
> +	if (f->dissector->used_keys &
> +	    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
> +	      BIT(FLOW_DISSECTOR_KEY_BASIC) |
> +	      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
> +	      BIT(FLOW_DISSECTOR_KEY_VLAN) |
> +	      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
> +	      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
> +	      BIT(FLOW_DISSECTOR_KEY_PORTS) |
> +	      BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
> +		dev_err(&pf->pdev->dev, "Unsupported key used: 0x%x\n",
> +			f->dissector->used_keys);
> +		return -EOPNOTSUPP;
> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
> +		struct flow_dissector_key_keyid *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_ENC_KEYID,
> +						  f->key);
> +
> +		struct flow_dissector_key_keyid *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_ENC_KEYID,
> +						  f->mask);
> +
> +		if (mask->keyid != 0)
> +			field_flags |= I40E_CLOUD_FIELD_TEN_ID;
> +
> +		filter->tenant_id = be32_to_cpu(key->keyid);
> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
> +		struct flow_dissector_key_basic *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_BASIC,
> +						  f->key);
> +
> +		filter->ip_proto = key->ip_proto;
> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
> +		struct flow_dissector_key_eth_addrs *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
> +						  f->key);
> +
> +		struct flow_dissector_key_eth_addrs *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_ETH_ADDRS,
> +						  f->mask);
> +
> +		/* use is_broadcast and is_zero to check for all 0xf or 0 */
> +		if (!is_zero_ether_addr(mask->dst)) {
> +			if (is_broadcast_ether_addr(mask->dst)) {
> +				field_flags |= I40E_CLOUD_FIELD_OMAC;
> +			} else {
> +				dev_err(&pf->pdev->dev, "Bad ether dest mask %pM\n",
> +					mask->dst);
> +				return I40E_ERR_CONFIG;
> +			}
> +		}
> +
> +		if (!is_zero_ether_addr(mask->src)) {
> +			if (is_broadcast_ether_addr(mask->src)) {
> +				field_flags |= I40E_CLOUD_FIELD_IMAC;
> +			} else {
> +				dev_err(&pf->pdev->dev, "Bad ether src mask %pM\n",
> +					mask->src);
> +				return I40E_ERR_CONFIG;
> +			}
> +		}
> +		ether_addr_copy(filter->dst_mac, key->dst);
> +		ether_addr_copy(filter->src_mac, key->src);
> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
> +		struct flow_dissector_key_vlan *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_VLAN,
> +						  f->key);
> +		struct flow_dissector_key_vlan *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_VLAN,
> +						  f->mask);
> +
> +		if (mask->vlan_id) {
> +			if (mask->vlan_id == VLAN_VID_MASK) {
> +				field_flags |= I40E_CLOUD_FIELD_IVLAN;
> +
> +			} else {
> +				dev_err(&pf->pdev->dev, "Bad vlan mask 0x%04x\n",
> +					mask->vlan_id);
> +				return I40E_ERR_CONFIG;
> +			}
> +		}
> +
> +		filter->vlan_id = cpu_to_be16(key->vlan_id);
> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
> +		struct flow_dissector_key_control *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_CONTROL,
> +						  f->key);
> +
> +		addr_type = key->addr_type;
> +	}
> +
> +	if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
> +		struct flow_dissector_key_ipv4_addrs *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
> +						  f->key);
> +		struct flow_dissector_key_ipv4_addrs *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_IPV4_ADDRS,
> +						  f->mask);
> +
> +		if (mask->dst) {
> +			if (mask->dst == cpu_to_be32(0xffffffff)) {
> +				field_flags |= I40E_CLOUD_FIELD_IIP;
> +			} else {
> +				dev_err(&pf->pdev->dev, "Bad ip dst mask 0x%08x\n",
> +					be32_to_cpu(mask->dst));
> +				return I40E_ERR_CONFIG;
> +			}
> +		}
> +
> +		if (mask->src) {
> +			if (mask->src == cpu_to_be32(0xffffffff)) {
> +				field_flags |= I40E_CLOUD_FIELD_IIP;
> +			} else {
> +				dev_err(&pf->pdev->dev, "Bad ip src mask 0x%08x\n",
> +					be32_to_cpu(mask->dst));
> +				return I40E_ERR_CONFIG;
> +			}
> +		}
> +
> +		if (field_flags & I40E_CLOUD_FIELD_TEN_ID) {
> +			dev_err(&pf->pdev->dev, "Tenant id not allowed for ip filter\n");
> +			return I40E_ERR_CONFIG;
> +		}
> +		filter->dst_ip = key->dst;
> +		filter->src_ip = key->src;
> +		filter->ip_version = IPV4_VERSION;
> +	}
> +
> +	if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
> +		struct flow_dissector_key_ipv6_addrs *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
> +						  f->key);
> +		struct flow_dissector_key_ipv6_addrs *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
> +						  f->mask);
> +
> +		/* src and dest IPV6 address should not be LOOPBACK
> +		 * (0:0:0:0:0:0:0:1), which can be represented as ::1
> +		 */
> +		if (ipv6_addr_loopback(&key->dst) ||
> +		    ipv6_addr_loopback(&key->src)) {
> +			dev_err(&pf->pdev->dev,
> +				"Bad ipv6, addr is LOOPBACK\n");
> +			return I40E_ERR_CONFIG;
> +		}
> +		if (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))
> +			field_flags |= I40E_CLOUD_FIELD_IIP;
> +
> +		memcpy(&filter->src_ipv6, &key->src.s6_addr32,
> +		       sizeof(filter->src_ipv6));
> +		memcpy(&filter->dst_ipv6, &key->dst.s6_addr32,
> +		       sizeof(filter->dst_ipv6));
> +
> +		/* mark it as IPv6 filter, to be used later */
> +		filter->ip_version = IPV6_VERSION;
> +	}
> +
> +	if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
> +		struct flow_dissector_key_ports *key =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_PORTS,
> +						  f->key);
> +		struct flow_dissector_key_ports *mask =
> +			skb_flow_dissector_target(f->dissector,
> +						  FLOW_DISSECTOR_KEY_PORTS,
> +						  f->mask);
> +
> +		if (mask->src) {
> +			if (mask->src == cpu_to_be16(0xffff)) {
> +				field_flags |= I40E_CLOUD_FIELD_IIP;
> +			} else {
> +				dev_err(&pf->pdev->dev, "Bad src port mask 0x%04x\n",

Consider using %pI4

> +					be16_to_cpu(mask->src));
> +				return I40E_ERR_CONFIG;
> +			}
> +		}
> +
> +		if (mask->dst) {
> +			if (mask->dst == cpu_to_be16(0xffff)) {
> +				field_flags |= I40E_CLOUD_FIELD_IIP;
> +			} else {
> +				dev_err(&pf->pdev->dev, "Bad dst port mask 0x%04x\n",

Consider using %pI4

> +					be16_to_cpu(mask->dst));
> +				return I40E_ERR_CONFIG;
> +			}
> +		}
> +
> +		filter->dst_port = key->dst;
> +		filter->src_port = key->src;
> +
> +		switch (filter->ip_proto) {
> +		case IPPROTO_TCP:
> +		case IPPROTO_UDP:
> +			break;
> +		default:
> +			dev_err(&pf->pdev->dev,
> +				"Only UDP and TCP transport are supported\n");
> +			return -EINVAL;
> +		}
> +	}
> +	filter->flags = field_flags;
> +	return 0;
> +}
> +
> +/**
> + * i40e_handle_tclass: Forward to a traffic class on the device
> + * @vsi: Pointer to VSI
> + * @tc: traffic class index on the device
> + * @filter: Pointer to cloud filter structure
> + *
> + **/
> +static int i40e_handle_tclass(struct i40e_vsi *vsi, u32 tc,
> +			      struct i40e_cloud_filter *filter)
> +{
> +	struct i40e_channel *ch, *ch_tmp;
> +
> +	/* direct to a traffic class on the same device */
> +	if (tc == 0) {
> +		filter->seid = vsi->seid;
> +		return 0;
> +	} else if (vsi->tc_config.enabled_tc & BIT(tc)) {
> +		if (!filter->dst_port) {
> +			dev_err(&vsi->back->pdev->dev,
> +				"Specify destination port to direct to traffic class that is not default\n");
> +			return -EINVAL;
> +		}
> +		if (list_empty(&vsi->ch_list))
> +			return -EINVAL;
> +		list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list,
> +					 list) {
> +			if (ch->seid == vsi->tc_seid_map[tc])
> +				filter->seid = ch->seid;
> +		}
> +		return 0;
> +	}
> +	dev_err(&vsi->back->pdev->dev, "TC is not enabled\n");
> +	return -EINVAL;
> +}
> +
> +/**
> + * i40e_configure_clsflower - Configure tc flower filters
> + * @vsi: Pointer to VSI
> + * @cls_flower: Pointer to struct tc_cls_flower_offload
> + *
> + **/
> +static int i40e_configure_clsflower(struct i40e_vsi *vsi,
> +				    struct tc_cls_flower_offload *cls_flower)
> +{
> +	u32 tc = TC_H_MIN(cls_flower->classid) - 1;
> +	struct i40e_cloud_filter *filter = NULL;
> +	struct i40e_pf *pf = vsi->back;
> +	int err = 0;
> +
> +	if (tc >= I40E_MAX_TRAFFIC_CLASS) {
> +		dev_err(&vsi->back->pdev->dev, "Invalid traffic class\n");
> +		return -EINVAL;
> +	}
> +
> +	if (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||
> +	    test_bit(__I40E_RESET_INTR_RECEIVED, pf->state))
> +		return -EBUSY;
> +
> +	if (pf->fdir_pf_active_filters ||
> +	    (!hlist_empty(&pf->fdir_filter_list))) {
> +		dev_err(&vsi->back->pdev->dev,
> +			"Flow Director Sideband filters exists, turn ntuple off to configure cloud filters\n");
> +		return -EINVAL;
> +	}
> +
> +	if (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) {
> +		dev_err(&vsi->back->pdev->dev,
> +			"Disable Flow Director Sideband, configuring Cloud filters via tc-flower\n");
> +		vsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED;
> +		vsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
> +	}
> +
> +	filter = kzalloc(sizeof(*filter), GFP_KERNEL);
> +	if (!filter)
> +		return -ENOMEM;
> +
> +	filter->cookie = cls_flower->cookie;
> +
> +	err = i40e_parse_cls_flower(vsi, cls_flower, filter);
> +	if (err < 0)
> +		goto err;
> +
> +	err = i40e_handle_tclass(vsi, tc, filter);
> +	if (err < 0)
> +		goto err;
> +
> +	/* Add cloud filter */
> +	if (filter->dst_port)
> +		err = i40e_add_del_cloud_filter_big_buf(vsi, filter, true);
> +	else
> +		err = i40e_add_del_cloud_filter(vsi, filter, true);
> +
> +	if (err) {
> +		dev_err(&pf->pdev->dev,
> +			"Failed to add cloud filter, err %s\n",
> +			i40e_stat_str(&pf->hw, err));
> +		err = i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);
> +		goto err;
> +	}
> +
> +	/* add filter to the ordered list */
> +	INIT_HLIST_NODE(&filter->cloud_node);
> +
> +	hlist_add_head(&filter->cloud_node, &pf->cloud_filter_list);
> +
> +	pf->num_cloud_filters++;
> +
> +	return err;
> +err:
> +	kfree(filter);
> +	return err;
> +}
> +
> +/**
> + * i40e_find_cloud_filter - Find the could filter in the list
> + * @vsi: Pointer to VSI
> + * @cookie: filter specific cookie
> + *
> + **/
> +static struct i40e_cloud_filter *i40e_find_cloud_filter(struct i40e_vsi *vsi,
> +							unsigned long *cookie)
> +{
> +	struct i40e_cloud_filter *filter = NULL;
> +	struct hlist_node *node2;
> +
> +	hlist_for_each_entry_safe(filter, node2,
> +				  &vsi->back->cloud_filter_list, cloud_node)
> +		if (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie)))
> +			return filter;
> +	return NULL;
> +}
> +
> +/**
> + * i40e_delete_clsflower - Remove tc flower filters
> + * @vsi: Pointer to VSI
> + * @cls_flower: Pointer to struct tc_cls_flower_offload
> + *
> + **/
> +static int i40e_delete_clsflower(struct i40e_vsi *vsi,
> +				 struct tc_cls_flower_offload *cls_flower)
> +{
> +	struct i40e_cloud_filter *filter = NULL;
> +	struct i40e_pf *pf = vsi->back;
> +	int err = 0;
> +
> +	filter = i40e_find_cloud_filter(vsi, &cls_flower->cookie);
> +
> +	if (!filter)
> +		return -EINVAL;
> +
> +	hash_del(&filter->cloud_node);
> +
> +	if (filter->dst_port)
> +		err = i40e_add_del_cloud_filter_big_buf(vsi, filter, false);
> +	else
> +		err = i40e_add_del_cloud_filter(vsi, filter, false);
> +	if (err) {
> +		kfree(filter);
> +		dev_err(&pf->pdev->dev,
> +			"Failed to delete cloud filter, err %s\n",
> +			i40e_stat_str(&pf->hw, err));
> +		return i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);
> +	}
> +
> +	kfree(filter);

Put this before your if (err) and you can take it out of the {} block

> +	pf->num_cloud_filters--;
> +
> +	if (!pf->num_cloud_filters)
> +		if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&
> +		    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {
> +			pf->flags |= I40E_FLAG_FD_SB_ENABLED;
> +			pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
> +			pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
> +		}
> +	return 0;
> +}
> +
> +/**
> + * i40e_setup_tc_cls_flower - flower classifier offloads
> + * @netdev: net device to configure
> + * @type_data: offload data
> + **/
> +static int i40e_setup_tc_cls_flower(struct net_device *netdev,
> +				    struct tc_cls_flower_offload *cls_flower)
> +{
> +	struct i40e_netdev_priv *np = netdev_priv(netdev);
> +	struct i40e_vsi *vsi = np->vsi;
> +
> +	if (!is_classid_clsact_ingress(cls_flower->common.classid) ||
> +	    cls_flower->common.chain_index)
> +		return -EOPNOTSUPP;
> +
> +	switch (cls_flower->command) {
> +	case TC_CLSFLOWER_REPLACE:
> +		return i40e_configure_clsflower(vsi, cls_flower);
> +	case TC_CLSFLOWER_DESTROY:
> +		return i40e_delete_clsflower(vsi, cls_flower);
> +	case TC_CLSFLOWER_STATS:
> +		return -EOPNOTSUPP;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
>   static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,
>   			   void *type_data)
>   {
> -	if (type != TC_SETUP_MQPRIO)
> +	switch (type) {
> +	case TC_SETUP_MQPRIO:
> +		return i40e_setup_tc(netdev, type_data);
> +	case TC_SETUP_CLSFLOWER:
> +		return i40e_setup_tc_cls_flower(netdev, type_data);
> +	default:
>   		return -EOPNOTSUPP;
> -
> -	return i40e_setup_tc(netdev, type_data);
> +	}
>   }
>   
>   /**
> @@ -6954,6 +7707,13 @@ static void i40e_cloud_filter_exit(struct i40e_pf *pf)
>   		kfree(cfilter);
>   	}
>   	pf->num_cloud_filters = 0;
> +
> +	if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&
> +	    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {
> +		pf->flags |= I40E_FLAG_FD_SB_ENABLED;
> +		pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
> +		pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
> +	}
>   }
>   
>   /**
> @@ -8061,7 +8821,8 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb)
>    * i40e_get_capabilities - get info about the HW
>    * @pf: the PF struct
>    **/
> -static int i40e_get_capabilities(struct i40e_pf *pf)
> +static int i40e_get_capabilities(struct i40e_pf *pf,
> +				 enum i40e_admin_queue_opc list_type)
>   {
>   	struct i40e_aqc_list_capabilities_element_resp *cap_buf;
>   	u16 data_size;
> @@ -8076,9 +8837,8 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
>   
>   		/* this loads the data into the hw struct for us */
>   		err = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,
> -					    &data_size,
> -					    i40e_aqc_opc_list_func_capabilities,
> -					    NULL);
> +						    &data_size, list_type,
> +						    NULL);
>   		/* data loaded, buffer no longer needed */
>   		kfree(cap_buf);
>   
> @@ -8095,26 +8855,44 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
>   		}
>   	} while (err);
>   
> -	if (pf->hw.debug_mask & I40E_DEBUG_USER)
> -		dev_info(&pf->pdev->dev,
> -			 "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n",
> -			 pf->hw.pf_id, pf->hw.func_caps.num_vfs,
> -			 pf->hw.func_caps.num_msix_vectors,
> -			 pf->hw.func_caps.num_msix_vectors_vf,
> -			 pf->hw.func_caps.fd_filters_guaranteed,
> -			 pf->hw.func_caps.fd_filters_best_effort,
> -			 pf->hw.func_caps.num_tx_qp,
> -			 pf->hw.func_caps.num_vsis);
> -
> +	if (pf->hw.debug_mask & I40E_DEBUG_USER) {
> +		if (list_type == i40e_aqc_opc_list_func_capabilities) {
> +			dev_info(&pf->pdev->dev,
> +				 "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n",
> +				 pf->hw.pf_id, pf->hw.func_caps.num_vfs,
> +				 pf->hw.func_caps.num_msix_vectors,
> +				 pf->hw.func_caps.num_msix_vectors_vf,
> +				 pf->hw.func_caps.fd_filters_guaranteed,
> +				 pf->hw.func_caps.fd_filters_best_effort,
> +				 pf->hw.func_caps.num_tx_qp,
> +				 pf->hw.func_caps.num_vsis);
> +		} else if (list_type == i40e_aqc_opc_list_dev_capabilities) {
> +			dev_info(&pf->pdev->dev,
> +				 "switch_mode=0x%04x, function_valid=0x%08x\n",
> +				 pf->hw.dev_caps.switch_mode,
> +				 pf->hw.dev_caps.valid_functions);
> +			dev_info(&pf->pdev->dev,
> +				 "SR-IOV=%d, num_vfs for all function=%u\n",
> +				 pf->hw.dev_caps.sr_iov_1_1,
> +				 pf->hw.dev_caps.num_vfs);
> +			dev_info(&pf->pdev->dev,
> +				 "num_vsis=%u, num_rx:%u, num_tx=%u\n",
> +				 pf->hw.dev_caps.num_vsis,
> +				 pf->hw.dev_caps.num_rx_qp,
> +				 pf->hw.dev_caps.num_tx_qp);
> +		}
> +	}
> +	if (list_type == i40e_aqc_opc_list_func_capabilities) {
>   #define DEF_NUM_VSI (1 + (pf->hw.func_caps.fcoe ? 1 : 0) \
>   		       + pf->hw.func_caps.num_vfs)
> -	if (pf->hw.revision_id == 0 && (DEF_NUM_VSI > pf->hw.func_caps.num_vsis)) {
> -		dev_info(&pf->pdev->dev,
> -			 "got num_vsis %d, setting num_vsis to %d\n",
> -			 pf->hw.func_caps.num_vsis, DEF_NUM_VSI);
> -		pf->hw.func_caps.num_vsis = DEF_NUM_VSI;
> +		if (pf->hw.revision_id == 0 &&
> +		    pf->hw.func_caps.num_vsis < DEF_NUM_VSI) {
> +			dev_info(&pf->pdev->dev,
> +				 "got num_vsis %d, setting num_vsis to %d\n",
> +				 pf->hw.func_caps.num_vsis, DEF_NUM_VSI);
> +			pf->hw.func_caps.num_vsis = DEF_NUM_VSI;
> +		}
>   	}
> -
>   	return 0;
>   }
>   
> @@ -8156,6 +8934,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
>   		if (!vsi) {
>   			dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n");
>   			pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
> +			pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>   			return;
>   		}
>   	}
> @@ -8178,6 +8957,48 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)
>   }
>   
>   /**
> + * i40e_rebuild_cloud_filters - Rebuilds cloud filters for VSIs
> + * @vsi: PF main vsi
> + * @seid: seid of main or channel VSIs
> + *
> + * Rebuilds cloud filters associated with main VSI and channel VSIs if they
> + * existed before reset
> + **/
> +static int i40e_rebuild_cloud_filters(struct i40e_vsi *vsi, u16 seid)
> +{
> +	struct i40e_cloud_filter *cfilter;
> +	struct i40e_pf *pf = vsi->back;
> +	struct hlist_node *node;
> +	i40e_status ret;
> +
> +	/* Add cloud filters back if they exist */
> +	if (hlist_empty(&pf->cloud_filter_list))
> +		return 0;

Is this necessary?  Doesn't hlist_for_each_entry_safe() do the right 
thing if the list is empty?

> +
> +	hlist_for_each_entry_safe(cfilter, node, &pf->cloud_filter_list,
> +				  cloud_node) {
> +		if (cfilter->seid != seid)
> +			continue;
> +
> +		if (cfilter->dst_port)
> +			ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,
> +								true);
> +		else
> +			ret = i40e_add_del_cloud_filter(vsi, cfilter, true);
> +
> +		if (ret) {
> +			dev_dbg(&pf->pdev->dev,
> +				"Failed to rebuild cloud filter, err %s aq_err %s\n",
> +				i40e_stat_str(&pf->hw, ret),
> +				i40e_aq_str(&pf->hw,
> +					    pf->hw.aq.asq_last_status));
> +			return ret;
> +		}
> +	}
> +	return 0;
> +}
> +
> +/**
>    * i40e_rebuild_channels - Rebuilds channel VSIs if they existed before reset
>    * @vsi: PF main vsi
>    *
> @@ -8216,6 +9037,13 @@ static int i40e_rebuild_channels(struct i40e_vsi *vsi)
>   				credits,
>   				ch->seid);
>   		}
> +		ret = i40e_rebuild_cloud_filters(vsi, ch->seid);
> +		if (ret) {
> +			dev_dbg(&vsi->back->pdev->dev,
> +				"Failed to rebuild cloud filters for channel VSI %u\n",
> +				ch->seid);
> +			return ret;
> +		}
>   	}
>   	return 0;
>   }
> @@ -8382,7 +9210,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
>   		i40e_verify_eeprom(pf);
>   
>   	i40e_clear_pxe_mode(hw);
> -	ret = i40e_get_capabilities(pf);
> +	ret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);
>   	if (ret)
>   		goto end_core_reset;
>   
> @@ -8503,6 +9331,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
>   			vsi->seid);
>   	}
>   
> +	ret = i40e_rebuild_cloud_filters(vsi, vsi->seid);
> +	if (ret)
> +		goto end_unlock;
> +
>   	/* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs
>   	 * for this main VSI if they exist
>   	 */
> @@ -9425,6 +10257,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
>   	    (pf->num_fdsb_msix == 0)) {
>   		dev_info(&pf->pdev->dev, "Sideband Flowdir disabled, not enough MSI-X vectors\n");
>   		pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
> +		pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>   	}
>   	if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&
>   	    (pf->num_vmdq_msix == 0)) {
> @@ -9542,6 +10375,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
>   				       I40E_FLAG_FD_SB_ENABLED	|
>   				       I40E_FLAG_FD_ATR_ENABLED	|
>   				       I40E_FLAG_VMDQ_ENABLED);
> +			pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>   
>   			/* rework the queue expectations without MSIX */
>   			i40e_determine_queue_usage(pf);
> @@ -10282,9 +11116,13 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
>   		/* Enable filters and mark for reset */
>   		if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
>   			need_reset = true;
> -		/* enable FD_SB only if there is MSI-X vector */
> -		if (pf->num_fdsb_msix > 0)
> +		/* enable FD_SB only if there is MSI-X vector and no cloud
> +		 * filters exist
> +		 */
> +		if (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {
>   			pf->flags |= I40E_FLAG_FD_SB_ENABLED;
> +			pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
> +		}
>   	} else {
>   		/* turn off filters, mark for reset and clear SW filter list */
>   		if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
> @@ -10293,6 +11131,8 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
>   		}
>   		pf->flags &= ~(I40E_FLAG_FD_SB_ENABLED |
>   			       I40E_FLAG_FD_SB_AUTO_DISABLED);
> +		pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
> +
>   		/* reset fd counters */
>   		pf->fd_add_err = 0;
>   		pf->fd_atr_cnt = 0;
> @@ -10354,6 +11194,12 @@ static int i40e_set_features(struct net_device *netdev,
>   	else
>   		i40e_vlan_stripping_disable(vsi);
>   
> +	if (!(features & NETIF_F_HW_TC) && pf->num_cloud_filters) {
> +		dev_err(&pf->pdev->dev,
> +			"Offloaded tc filters active, can't turn hw_tc_offload off");
> +		return -EINVAL;
> +	}
> +
>   	need_reset = i40e_set_ntuple(pf, features);
>   
>   	if (need_reset)
> @@ -10873,7 +11719,8 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
>   	netdev->vlan_features |= hw_enc_features | NETIF_F_TSO_MANGLEID;
>   
>   	if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
> -		netdev->hw_features |= NETIF_F_NTUPLE;
> +		netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC;
> +
>   	hw_features = hw_enc_features		|
>   		      NETIF_F_HW_VLAN_CTAG_TX	|
>   		      NETIF_F_HW_VLAN_CTAG_RX;
> @@ -12178,8 +13025,10 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
>   	*/
>   
>   	if ((pf->hw.pf_id == 0) &&
> -	    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))
> +	    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {
>   		flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
> +		pf->last_sw_conf_flags = flags;
> +	}
>   
>   	if (pf->hw.pf_id == 0) {
>   		u16 valid_flags;
> @@ -12195,6 +13044,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
>   					     pf->hw.aq.asq_last_status));
>   			/* not a fatal problem, just keep going */
>   		}
> +		pf->last_sw_conf_valid_flags = valid_flags;
>   	}
>   
>   	/* first time setup */
> @@ -12292,6 +13142,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
>   			       I40E_FLAG_DCB_ENABLED	|
>   			       I40E_FLAG_SRIOV_ENABLED	|
>   			       I40E_FLAG_VMDQ_ENABLED);
> +		pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>   	} else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED |
>   				  I40E_FLAG_FD_SB_ENABLED |
>   				  I40E_FLAG_FD_ATR_ENABLED |
> @@ -12306,6 +13157,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
>   			       I40E_FLAG_FD_ATR_ENABLED	|
>   			       I40E_FLAG_DCB_ENABLED	|
>   			       I40E_FLAG_VMDQ_ENABLED);
> +		pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>   	} else {
>   		/* Not enough queues for all TCs */
>   		if ((pf->flags & I40E_FLAG_DCB_CAPABLE) &&
> @@ -12329,6 +13181,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
>   			queues_left -= 1; /* save 1 queue for FD */
>   		} else {
>   			pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
> +			pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>   			dev_info(&pf->pdev->dev, "not enough queues for Flow Director. Flow Director feature is disabled\n");
>   		}
>   	}
> @@ -12632,7 +13485,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>   		dev_warn(&pdev->dev, "This device is a pre-production adapter/LOM. Please be aware there may be issues with your hardware. If you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\n");
>   
>   	i40e_clear_pxe_mode(hw);
> -	err = i40e_get_capabilities(pf);
> +	err = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);
>   	if (err)
>   		goto err_adminq_setup;
>   
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> index 92869f5..3bb6659 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> @@ -283,6 +283,22 @@ i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,
>   		struct i40e_asq_cmd_details *cmd_details);
>   i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,
>   				   struct i40e_asq_cmd_details *cmd_details);
> +i40e_status
> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
> +			     struct i40e_aqc_cloud_filters_element_bb *filters,
> +			     u8 filter_count);
> +enum i40e_status_code
> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 vsi,
> +			  struct i40e_aqc_cloud_filters_element_data *filters,
> +			  u8 filter_count);
> +enum i40e_status_code
> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 vsi,
> +			  struct i40e_aqc_cloud_filters_element_data *filters,
> +			  u8 filter_count);
> +i40e_status
> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
> +			     struct i40e_aqc_cloud_filters_element_bb *filters,
> +			     u8 filter_count);
>   i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
>   			       struct i40e_lldp_variables *lldp_cfg);
>   /* i40e_common */
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
> index 24589a4..5577b6f 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
> @@ -291,6 +291,7 @@ struct i40e_hw_capabilities {
>   #define I40E_NVM_IMAGE_TYPE_MODE1	0x6
>   #define I40E_NVM_IMAGE_TYPE_MODE2	0x7
>   #define I40E_NVM_IMAGE_TYPE_MODE3	0x8
> +#define I40E_SWITCH_MODE_MASK		0xF
>   
>   	u32  management_mode;
>   	u32  mng_protocols_over_mctp;
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> index 0c4ff18..31135bd 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> @@ -1360,6 +1360,9 @@ struct i40e_aqc_cloud_filters_element_data {
>   		struct {
>   			u8 data[16];
>   		} v6;
> +		struct {
> +			__le16 data[8];
> +		} raw_v6;
>   	} ipaddr;
>   	__le16	flags;
>   #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT			0
> 
> _______________________________________________
> Intel-wired-lan mailing list
> Intel-wired-lan@osuosl.org
> https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
> 

^ permalink raw reply

* Re: [Intel-wired-lan] [jkirsher/next-queue PATCH v4 5/6] i40e: Clean up of cloud filters
From: Shannon Nelson @ 2017-10-11 23:30 UTC (permalink / raw)
  To: intel-wired-lan, Amritha Nambiar; +Cc: netdev@vger.kernel.org
In-Reply-To: <150768147910.5320.12192807833176784033.stgit@anamdev.jf.intel.com>

On 10/10/2017 5:24 PM, Amritha Nambiar wrote:
> Introduce the cloud filter datastructure and cleanup of cloud
> filters associated with the device.
> 
> v2: Moved field comments in struct i40e_cloud_filter to the right.
> Removed hlist_empty check from i40e_cloud_filter_exit()
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> ---
>   drivers/net/ethernet/intel/i40e/i40e.h      |    9 +++++++++
>   drivers/net/ethernet/intel/i40e/i40e_main.c |   24 ++++++++++++++++++++++++
>   2 files changed, 33 insertions(+)
> 
> diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
> index f3c501e..b938bb4a 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e.h
> @@ -253,6 +253,12 @@ struct i40e_fdir_filter {
>   	u32 fd_id;
>   };
>   
> +struct i40e_cloud_filter {
> +	struct hlist_node cloud_node;
> +	unsigned long cookie;
> +	u16 seid;	/* filter control */
> +};
> +
>   #define I40E_ETH_P_LLDP			0x88cc
>   
>   #define I40E_DCB_PRIO_TYPE_STRICT	0
> @@ -420,6 +426,9 @@ struct i40e_pf {
>   	struct i40e_udp_port_config udp_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
>   	u16 pending_udp_bitmap;
>   
> +	struct hlist_head cloud_filter_list;
> +	u16 num_cloud_filters;
> +
>   	enum i40e_interrupt_policy int_policy;
>   	u16 rx_itr_default;
>   	u16 tx_itr_default;
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index 0539d43..bcdb16a 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
> @@ -6937,6 +6937,26 @@ static void i40e_fdir_filter_exit(struct i40e_pf *pf)
>   }
>   
>   /**
> + * i40e_cloud_filter_exit - Cleans up the Cloud Filters
> + * @pf: Pointer to PF
> + *
> + * This function destroys the hlist where all the Cloud Filters
> + * filters were saved.

Redundant "Cloud Filters filters"

> + **/
> +static void i40e_cloud_filter_exit(struct i40e_pf *pf)
> +{
> +	struct i40e_cloud_filter *cfilter;
> +	struct hlist_node *node;
> +
> +	hlist_for_each_entry_safe(cfilter, node,
> +				  &pf->cloud_filter_list, cloud_node) {
> +		hlist_del(&cfilter->cloud_node);
> +		kfree(cfilter);
> +	}
> +	pf->num_cloud_filters = 0;
> +}
> +
> +/**
>    * i40e_close - Disables a network interface
>    * @netdev: network interface device structure
>    *
> @@ -12195,6 +12215,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
>   			vsi = i40e_vsi_reinit_setup(pf->vsi[pf->lan_vsi]);
>   		if (!vsi) {
>   			dev_info(&pf->pdev->dev, "setup of MAIN VSI failed\n");
> +			i40e_cloud_filter_exit(pf);
>   			i40e_fdir_teardown(pf);
>   			return -EAGAIN;
>   		}
> @@ -13029,6 +13050,8 @@ static void i40e_remove(struct pci_dev *pdev)
>   	if (pf->vsi[pf->lan_vsi])
>   		i40e_vsi_release(pf->vsi[pf->lan_vsi]);
>   
> +	i40e_cloud_filter_exit(pf);
> +
>   	/* remove attached clients */
>   	if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
>   		ret_code = i40e_lan_del_device(pf);
> @@ -13260,6 +13283,7 @@ static void i40e_shutdown(struct pci_dev *pdev)
>   
>   	del_timer_sync(&pf->service_timer);
>   	cancel_work_sync(&pf->service_task);
> +	i40e_cloud_filter_exit(pf);
>   	i40e_fdir_teardown(pf);
>   
>   	/* Client close must be called explicitly here because the timer
> 
> _______________________________________________
> Intel-wired-lan mailing list
> Intel-wired-lan@osuosl.org
> https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
> 

^ permalink raw reply

* Re: [Intel-wired-lan] [jkirsher/next-queue PATCH v4 4/6] i40e: Admin queue definitions for cloud filters
From: Shannon Nelson @ 2017-10-11 23:30 UTC (permalink / raw)
  To: intel-wired-lan, Amritha Nambiar; +Cc: netdev@vger.kernel.org
In-Reply-To: <150768147360.5320.13399379759470371200.stgit@anamdev.jf.intel.com>

On 10/10/2017 5:24 PM, Amritha Nambiar wrote:
> Add new admin queue definitions and extended fields for cloud
> filter support. Define big buffer for extended general fields
> in Add/Remove Cloud filters command.
> 
> v3: Shortened some lengthy struct names.
> v2: Added I40E_CHECK_STRUCT_LEN check to AQ command structs and
> added AQ definitions to i40evf for consistency based on Shannon's
> feedback.
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Signed-off-by: Kiran Patil <kiran.patil@intel.com>
> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>
> ---
>   drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |  110 ++++++++++++++++++++
>   .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |  110 ++++++++++++++++++++
>   2 files changed, 216 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> index 729976b..bcc7986 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> @@ -1371,14 +1371,16 @@ struct i40e_aqc_add_remove_cloud_filters {
>   #define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT	0
>   #define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK	(0x3FF << \
>   					I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT)
> -	u8	reserved2[4];
> +	u8	big_buffer_flag;
> +#define I40E_AQC_ADD_CLOUD_CMD_BB	1
> +	u8	reserved2[3];
>   	__le32	addr_high;
>   	__le32	addr_low;
>   };
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_cloud_filters);
>   
> -struct i40e_aqc_add_remove_cloud_filters_element_data {
> +struct i40e_aqc_cloud_filters_element_data {
>   	u8	outer_mac[6];
>   	u8	inner_mac[6];
>   	__le16	inner_vlan;
> @@ -1408,6 +1410,13 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
>   #define I40E_AQC_ADD_CLOUD_FILTER_IMAC			0x000A
>   #define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC	0x000B
>   #define I40E_AQC_ADD_CLOUD_FILTER_IIP			0x000C
> +/* 0x0010 to 0x0017 is for custom filters */
> +/* flag to be used when adding cloud filter: IP + L4 Port */
> +#define I40E_AQC_ADD_CLOUD_FILTER_IP_PORT		0x0010
> +/* flag to be used when adding cloud filter: Dest MAC + L4 Port */
> +#define I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT		0x0011
> +/* flag to be used when adding cloud filter: Dest MAC + VLAN + L4 Port */
> +#define I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT		0x0012

Short description comments to the side of each line would be more 
readable, and maybe don't mind too much the 80 column thing here

#define I40E_AQC_ADD_CLOUD_FILTER_IP_PORT	0x0010/* Dest IP + L4 Port */
#define I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT	0x0011 /* Dest MAC + L4 Port */
#define I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT	0x0012 /* Dest MAC + 
VLAN + L4 Port */


>   
>   #define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE		0x0080
>   #define I40E_AQC_ADD_CLOUD_VNK_SHIFT			6
> @@ -1442,6 +1451,49 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
>   	u8	response_reserved[7];
>   };
>   
> +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_cloud_filters_element_data);
> +
> +/* i40e_aqc_cloud_filters_element_bb is used when
> + * I40E_AQC_CLOUD_CMD_BB flag is set.
> + */
> +struct i40e_aqc_cloud_filters_element_bb {
> +	struct i40e_aqc_cloud_filters_element_data element;
> +	u16     general_fields[32];
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0	0
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1	1
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2	2
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0	3
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1	4
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2	5
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0	6
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1	7
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2	8
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0	9
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1	10
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2	11
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD0	12
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD1	13
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD2	14
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0	15
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD1	16
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD2	17
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD3	18
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD4	19
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD5	20
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD6	21
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD7	22
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD0	23
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD1	24
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD2	25
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD3	26
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD4	27
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD5	28
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD6	29
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD7	30
> +};
> +
> +I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_cloud_filters_element_bb);
> +
>   struct i40e_aqc_remove_cloud_filters_completion {
>   	__le16 perfect_ovlan_used;
>   	__le16 perfect_ovlan_free;
> @@ -1453,6 +1505,60 @@ struct i40e_aqc_remove_cloud_filters_completion {
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_cloud_filters_completion);
>   
> +/* Replace filter Command 0x025F
> + * uses the i40e_aqc_replace_cloud_filters,
> + * and the generic indirect completion structure
> + */
> +struct i40e_filter_data {
> +	u8 filter_type;
> +	u8 input[3];
> +};
> +
> +I40E_CHECK_STRUCT_LEN(4, i40e_filter_data);
> +
> +struct i40e_aqc_replace_cloud_filters_cmd {
> +	u8      valid_flags;
> +#define I40E_AQC_REPLACE_L1_FILTER		0x0
> +#define I40E_AQC_REPLACE_CLOUD_FILTER		0x1
> +#define I40E_AQC_GET_CLOUD_FILTERS		0x2
> +#define I40E_AQC_MIRROR_CLOUD_FILTER		0x4
> +#define I40E_AQC_HIGH_PRIORITY_CLOUD_FILTER	0x8
> +	u8      old_filter_type;
> +	u8      new_filter_type;
> +	u8      tr_bit;
> +	u8      reserved[4];
> +	__le32 addr_high;
> +	__le32 addr_low;
> +};
> +
> +I40E_CHECK_CMD_LENGTH(i40e_aqc_replace_cloud_filters_cmd);
> +
> +struct i40e_aqc_replace_cloud_filters_cmd_buf {
> +	u8      data[32];
> +/* Filter type INPUT codes*/
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_ENTRIES_MAX	3
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED	BIT(7)
> +
> +/* Field Vector offsets */
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_MAC_DA	0
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_ETH	6
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG	7
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_VLAN	8
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_OVLAN	9
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN	10
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY	11
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC	12
> +/* big FLU */
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IP_DA	14
> +/* big FLU */
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_OIP_DA	15
> +
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_INNER_VLAN	37
> +	struct i40e_filter_data filters[8];
> +};
> +
> +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_replace_cloud_filters_cmd_buf);
> +
>   /* Add Mirror Rule (indirect or direct 0x0260)
>    * Delete Mirror Rule (indirect or direct 0x0261)
>    * note: some rule types (4,5) do not use an external buffer.
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> index 463e331..0c4ff18 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> @@ -1339,14 +1339,16 @@ struct i40e_aqc_add_remove_cloud_filters {
>   #define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT	0
>   #define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK	(0x3FF << \
>   					I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT)
> -	u8	reserved2[4];
> +	u8	big_buffer_flag;
> +#define I40E_AQC_ADD_CLOUD_CMD_BB	1
> +	u8	reserved2[3];
>   	__le32	addr_high;
>   	__le32	addr_low;
>   };
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_cloud_filters);
>   
> -struct i40e_aqc_add_remove_cloud_filters_element_data {
> +struct i40e_aqc_cloud_filters_element_data {
>   	u8	outer_mac[6];
>   	u8	inner_mac[6];
>   	__le16	inner_vlan;
> @@ -1376,6 +1378,13 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
>   #define I40E_AQC_ADD_CLOUD_FILTER_IMAC			0x000A
>   #define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC	0x000B
>   #define I40E_AQC_ADD_CLOUD_FILTER_IIP			0x000C
> +/* 0x0010 to 0x0017 is for custom filters */
> +/* flag to be used when adding cloud filter: IP + L4 Port */
> +#define I40E_AQC_ADD_CLOUD_FILTER_IP_PORT		0x0010
> +/* flag to be used when adding cloud filter: Dest MAC + L4 Port */
> +#define I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT		0x0011
> +/* flag to be used when adding cloud filter: Dest MAC + VLAN + L4 Port */
> +#define I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT		0x0012
>   
>   #define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE		0x0080
>   #define I40E_AQC_ADD_CLOUD_VNK_SHIFT			6
> @@ -1410,6 +1419,49 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
>   	u8	response_reserved[7];
>   };
>   
> +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_cloud_filters_element_data);
> +
> +/* i40e_aqc_cloud_filters_element_bb is used when
> + * I40E_AQC_ADD_CLOUD_CMD_BB flag is set.
> + */
> +struct i40e_aqc_cloud_filters_element_bb {
> +	struct i40e_aqc_cloud_filters_element_data element;
> +	u16     general_fields[32];
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0	0
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1	1
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2	2
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0	3
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1	4
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2	5
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0	6
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1	7
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2	8
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0	9
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1	10
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2	11
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD0	12
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD1	13
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD2	14
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0	15
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD1	16
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD2	17
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD3	18
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD4	19
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD5	20
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD6	21
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD7	22
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD0	23
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD1	24
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD2	25
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD3	26
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD4	27
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD5	28
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD6	29
> +#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD7	30
> +};
> +
> +I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_cloud_filters_element_bb);
> +
>   struct i40e_aqc_remove_cloud_filters_completion {
>   	__le16 perfect_ovlan_used;
>   	__le16 perfect_ovlan_free;
> @@ -1421,6 +1473,60 @@ struct i40e_aqc_remove_cloud_filters_completion {
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_cloud_filters_completion);
>   
> +/* Replace filter Command 0x025F
> + * uses the i40e_aqc_replace_cloud_filters,
> + * and the generic indirect completion structure
> + */
> +struct i40e_filter_data {
> +	u8 filter_type;
> +	u8 input[3];
> +};
> +
> +I40E_CHECK_STRUCT_LEN(4, i40e_filter_data);
> +
> +struct i40e_aqc_replace_cloud_filters_cmd {
> +	u8      valid_flags;
> +#define I40E_AQC_REPLACE_L1_FILTER		0x0
> +#define I40E_AQC_REPLACE_CLOUD_FILTER		0x1
> +#define I40E_AQC_GET_CLOUD_FILTERS		0x2
> +#define I40E_AQC_MIRROR_CLOUD_FILTER		0x4
> +#define I40E_AQC_HIGH_PRIORITY_CLOUD_FILTER	0x8
> +	u8      old_filter_type;
> +	u8      new_filter_type;
> +	u8      tr_bit;
> +	u8      reserved[4];
> +	__le32 addr_high;
> +	__le32 addr_low;
> +};
> +
> +I40E_CHECK_CMD_LENGTH(i40e_aqc_replace_cloud_filters_cmd);
> +
> +struct i40e_aqc_replace_cloud_filters_cmd_buf {
> +	u8      data[32];
> +/* Filter type INPUT codes*/
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_ENTRIES_MAX	3
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED	BIT(7)
> +
> +/* Field Vector offsets */
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_MAC_DA	0
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_ETH	6
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG	7
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_VLAN	8
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_OVLAN	9
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN	10
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY	11
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC	12
> +/* big FLU */
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IP_DA	14
> +/* big FLU */
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_OIP_DA	15
> +
> +#define I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_INNER_VLAN	37
> +	struct i40e_filter_data filters[8];
> +};
> +
> +I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_replace_cloud_filters_cmd_buf);
> +
>   /* Add Mirror Rule (indirect or direct 0x0260)
>    * Delete Mirror Rule (indirect or direct 0x0261)
>    * note: some rule types (4,5) do not use an external buffer.
> 
> _______________________________________________
> Intel-wired-lan mailing list
> Intel-wired-lan@osuosl.org
> https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
> 

^ permalink raw reply

* Re: [Intel-wired-lan] [jkirsher/next-queue PATCH v4 3/6] i40e: Cloud filter mode for set_switch_config command
From: Shannon Nelson @ 2017-10-11 23:30 UTC (permalink / raw)
  To: intel-wired-lan, Amritha Nambiar; +Cc: netdev@vger.kernel.org
In-Reply-To: <150768146806.5320.1212910477662310789.stgit@anamdev.jf.intel.com>

On 10/10/2017 5:24 PM, Amritha Nambiar wrote:
> Add definitions for L4 filters and switch modes based on cloud filters
> modes and extend the set switch config command to include the
> additional cloud filter mode.
> 
> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>
> Signed-off-by: Kiran Patil <kiran.patil@intel.com>
> ---
>   drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h |   30 ++++++++++++++++++++-
>   drivers/net/ethernet/intel/i40e/i40e_common.c     |    4 ++-
>   drivers/net/ethernet/intel/i40e/i40e_ethtool.c    |    2 +
>   drivers/net/ethernet/intel/i40e/i40e_main.c       |    2 +
>   drivers/net/ethernet/intel/i40e/i40e_prototype.h  |    2 +
>   drivers/net/ethernet/intel/i40e/i40e_type.h       |    9 ++++++
>   6 files changed, 44 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> index 6a5db1b..729976b 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> @@ -790,7 +790,35 @@ struct i40e_aqc_set_switch_config {
>   	 */
>   	__le16	first_tag;
>   	__le16	second_tag;
> -	u8	reserved[6];
> +	/* Next byte is split into following:
> +	 * Bit 7 : 0: No action, 1: Switch to mode defined by bits 6:0
> +	 * Bit 6: 0 : Destination Port, 1: source port
> +	 * Bit 5..4: L4 type

Can you tweak the formatting on these comments to line up the first 
couple of ':'s?

> +	 * 0: rsvd
> +	 * 1: TCP
> +	 * 2: UDP
> +	 * 3: Both TCP and UDP
> +	 * Bits 3:0 Mode
> +	 * 0: default mode
> +	 * 1: L4 port only mode
> +	 * 2: non-tunneled mode
> +	 * 3: tunneled mode
> +	 */
> +#define I40E_AQ_SET_SWITCH_BIT7_VALID		0x80
> +
> +#define I40E_AQ_SET_SWITCH_L4_SRC_PORT		0x40
> +
> +#define I40E_AQ_SET_SWITCH_L4_TYPE_RSVD		0x00
> +#define I40E_AQ_SET_SWITCH_L4_TYPE_TCP		0x10
> +#define I40E_AQ_SET_SWITCH_L4_TYPE_UDP		0x20
> +#define I40E_AQ_SET_SWITCH_L4_TYPE_BOTH		0x30
> +
> +#define I40E_AQ_SET_SWITCH_MODE_DEFAULT		0x00
> +#define I40E_AQ_SET_SWITCH_MODE_L4_PORT		0x01
> +#define I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL	0x02
> +#define I40E_AQ_SET_SWITCH_MODE_TUNNEL		0x03
> +	u8	mode;
> +	u8	rsvd5[5];
>   };
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
> index 1b85eb3..0b3c5b7 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
> @@ -2402,13 +2402,14 @@ i40e_status i40e_aq_get_switch_config(struct i40e_hw *hw,
>    * @hw: pointer to the hardware structure
>    * @flags: bit flag values to set
>    * @valid_flags: which bit flags to set
> + * @mode: cloud filter mode
>    * @cmd_details: pointer to command details structure or NULL
>    *
>    * Set switch configuration bits
>    **/
>   enum i40e_status_code i40e_aq_set_switch_config(struct i40e_hw *hw,
>   						u16 flags,
> -						u16 valid_flags,
> +						u16 valid_flags, u8 mode,
>   				struct i40e_asq_cmd_details *cmd_details)
>   {
>   	struct i40e_aq_desc desc;
> @@ -2420,6 +2421,7 @@ enum i40e_status_code i40e_aq_set_switch_config(struct i40e_hw *hw,
>   					  i40e_aqc_opc_set_switch_config);
>   	scfg->flags = cpu_to_le16(flags);
>   	scfg->valid_flags = cpu_to_le16(valid_flags);
> +	scfg->mode = mode;
>   	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
>   		scfg->switch_tag = cpu_to_le16(hw->switch_tag);
>   		scfg->first_tag = cpu_to_le16(hw->first_tag);
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
> index a760d75..37ca294 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
> @@ -4341,7 +4341,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
>   			sw_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
>   		valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
>   		ret = i40e_aq_set_switch_config(&pf->hw, sw_flags, valid_flags,
> -						NULL);
> +						0, NULL);
>   		if (ret && pf->hw.aq.asq_last_status != I40E_AQ_RC_ESRCH) {
>   			dev_info(&pf->pdev->dev,
>   				 "couldn't set switch config bits, err %s aq_err %s\n",
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
> index 33a8f429..0539d43 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
> @@ -12165,7 +12165,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
>   		u16 valid_flags;
>   
>   		valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
> -		ret = i40e_aq_set_switch_config(&pf->hw, flags, valid_flags,
> +		ret = i40e_aq_set_switch_config(&pf->hw, flags, valid_flags, 0,
>   						NULL);
>   		if (ret && pf->hw.aq.asq_last_status != I40E_AQ_RC_ESRCH) {
>   			dev_info(&pf->pdev->dev,
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> index 0150256..92869f5 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> @@ -190,7 +190,7 @@ i40e_status i40e_aq_get_switch_config(struct i40e_hw *hw,
>   				struct i40e_asq_cmd_details *cmd_details);
>   enum i40e_status_code i40e_aq_set_switch_config(struct i40e_hw *hw,
>   						u16 flags,
> -						u16 valid_flags,
> +						u16 valid_flags, u8 mode,
>   				struct i40e_asq_cmd_details *cmd_details);
>   i40e_status i40e_aq_request_resource(struct i40e_hw *hw,
>   				enum i40e_aq_resources_ids resource,
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
> index 17a99b5..24589a4 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
> @@ -283,6 +283,15 @@ struct i40e_hw_capabilities {
>   #define I40E_NVM_IMAGE_TYPE_CLOUD	0x2
>   #define I40E_NVM_IMAGE_TYPE_UDP_CLOUD	0x3
>   
> +	/* Cloud filter modes:
> +	 * Mode1: Filter on L4 port only
> +	 * Mode2: Filter for non-tunneled traffic
> +	 * Mode3: Filter for tunnel traffic
> +	 */
> +#define I40E_NVM_IMAGE_TYPE_MODE1	0x6
> +#define I40E_NVM_IMAGE_TYPE_MODE2	0x7
> +#define I40E_NVM_IMAGE_TYPE_MODE3	0x8

These names aren't very descriptive... out of context these look like 
they are describing NVM image types, not message filter types.

> +
>   	u32  management_mode;
>   	u32  mng_protocols_over_mctp;
>   #define I40E_MNG_PROTOCOL_PLDM		0x2
> 
> _______________________________________________
> Intel-wired-lan mailing list
> Intel-wired-lan@osuosl.org
> https://lists.osuosl.org/mailman/listinfo/intel-wired-lan
> 

^ permalink raw reply

* Re: [PATCH net-next 0/7] Rewrite some existing functionality
From: Subash Abhinov Kasiviswanathan @ 2017-10-11 23:11 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20171011.152518.927596165753645888.davem@davemloft.net>

On 2017-10-11 16:25, David Miller wrote:
> From: David Miller <davem@davemloft.net>
> Date: Wed, 11 Oct 2017 15:22:59 -0700 (PDT)
> 
>> From: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
>> Date: Tue, 10 Oct 2017 22:17:29 -0600
>> 
>>> This series fixes some of the broken rmnet functionality.
>>> Bridge mode is re-written and made useable and the muxed_ep is 
>>> converted to hlist.
>>> 
>>> Patches 1-5 are cleanups in preparation for these changes.
>>> Patch 6 does the hlist conversion.
>>> Patch 7 has the implementation of the rmnet bridge mode.
>> 
>> Series applied, thank you.
> 
> Actually, I reverted:
> 
> drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c: In function
> ‘rmnet_rx_handler’:
> drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c:174:6: warning:
> ‘rc’ may be used uninitialized in this function
> [-Wmaybe-uninitialized]
>   int rc;
>       ^~
> 
> Also, the indentation of the switch statement is wrong, the break
> statements need to be indented the same as the rest of the code
> in their switch statements.

Hi David

I'll fix this and upload v2.
Somehow my compiler didnt throw this warning even though i have -Wall 
set.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [PATCH 0/4] net: qcom/emac: various minor fixes
From: David Miller @ 2017-10-11 23:02 UTC (permalink / raw)
  To: timur; +Cc: netdev
In-Reply-To: <1507751546-10265-1-git-send-email-timur@codeaurora.org>

From: Timur Tabi <timur@codeaurora.org>
Date: Wed, 11 Oct 2017 14:52:22 -0500

> A set of patches for 4.15 that clean up some code, apply minors fixes,
> and so on.  Some of the code also prepares the driver for a future 
> version of the EMAC controller.

Series applied, thank you.

^ permalink raw reply

* Re: [PATCH] i40e/i40evf: actually use u32 for feature flags
From: Jeff Kirsher @ 2017-10-11 22:46 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Jacob Keller, Alexander Duyck, Mitch Williams, Filip Sadowski,
	intel-wired-lan, netdev, linux-kernel
In-Reply-To: <20171011140316.3802721-1-arnd@arndb.de>

On Wed, 2017-10-11 at 16:02 +0200, Arnd Bergmann wrote:
> A previous cleanup intended to change the flags variable to 32
> bit instead of 64, but accidentally left out the important
> part of that change, leading to a build error:
> 
> drivers/net/ethernet/intel/i40e/i40e_ethtool.o: In function
> `i40e_set_priv_flags':
> i40e_ethtool.c:(.text+0x1a94): undefined reference to
> `wrong_size_cmpxchg'
> 
> This adds the missing modification.
> 
> Fixes: b74f571f59a8 ("i40e/i40evf: organize and re-number feature
> flags")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/net/ethernet/intel/i40e/i40e.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

To slow... :-) I had already sent a fix for this on Monday to David. 
Check David Miller's net-next tree, it is already there.

^ permalink raw reply

* Re: [jkirsher/next-queue PATCH v4 0/6] tc-flower based cloud filters in i40e
From: Nambiar, Amritha @ 2017-10-11 22:41 UTC (permalink / raw)
  To: Jamal Hadi Salim, intel-wired-lan, jeffrey.t.kirsher
  Cc: alexander.h.duyck, jiri, netdev, alexander.duyck, xiyou.wangcong
In-Reply-To: <f85aa039-cf16-a25a-5b60-1af747b44f62@mojatatu.com>

On 10/11/2017 5:42 AM, Jamal Hadi Salim wrote:
> On 17-10-10 08:24 PM, Amritha Nambiar wrote:
>> This patch series enables configuring cloud filters in i40e
>> using the tc-flower classifier. The classification function
>> of the filter is to match a packet to a class. cls_flower is
>> extended to offload classid to hardware. The offloaded classid
>> is used direct matched packets to a traffic class on the device.
>> The approach here is similar to the tc 'prio' qdisc which uses
>> the classid for band selection. The ingress qdisc is called ffff:0,
>> so traffic classes are ffff:1 to ffff:8 (i40e has max of 8 TCs).
>> TC0 is minor number 1, TC1 is minor number 2 etc.
>>
>> The cloud filters are added for a VSI and are cleaned up when
>> the VSI is deleted. The filters that match on L4 ports needs
>> enhanced admin queue functions with big buffer support for
>> extended fields in cloud filter commands.
>>
>> Example:
>> # tc qdisc add dev eth0 ingress
>> # ethtool -K eth0 hw-tc-offload on
>>
>> Match Dst IPv4,Dst Port and route to TC1:
>> # tc filter add dev eth0 protocol ip parent ffff: prio 1 flower\
>>    dst_ip 192.168.1.1/32 ip_proto udp dst_port 22\
>>    skip_sw classid ffff:2
>>
>> # tc filter show dev eth0 parent ffff:
>> filter pref 1 flower chain 0
>> filter pref 1 flower chain 0 handle 0x1 classid ffff:2
>>    eth_type ipv4
>>    ip_proto udp
>>    dst_ip 192.168.1.1
>>    dst_port 22
>>    skip_sw
>>    in_hw
>>
> 
> Much much better semantic. Thank you.
> Have you tested many filter mapping to the same classid?

Yes, I have tested mapping different filters to the same classID,
packets matching the flows were assigned the same classID and routed to
the same traffic class in HW.

filter pref 1 flower chain 0
filter pref 1 flower chain 0 handle 0x1 classid ffff:2
  dst_mac 3c:fd:fe:a0:d6:70
  eth_type ipv4
  ip_proto udp
  dst_port 12000
  in_hw
filter pref 5 flower chain 0
filter pref 5 flower chain 0 handle 0x1 classid ffff:2
  eth_type ipv4
  ip_proto udp
  dst_ip 192.168.1.1
  dst_port 12000
  in_hw

> 
> cheers,
> jamal
> 

^ permalink raw reply

* Re: [PATCH v2 0/7] net: qrtr: Fixes and support receiving version 2 packets
From: David Miller @ 2017-10-11 22:38 UTC (permalink / raw)
  To: bjorn.andersson; +Cc: netdev, linux-kernel, linux-arm-msm, clew
In-Reply-To: <20171011064523.7902-1-bjorn.andersson@linaro.org>

From: Bjorn Andersson <bjorn.andersson@linaro.org>
Date: Tue, 10 Oct 2017 23:45:16 -0700

> On the latest Qualcomm platforms remote processors are sending packets with
> version 2 of the message header. This series starts off with some fixes and
> then refactors the qrtr code to support receiving messages of both version 1
> and version 2.
> 
> As all remotes are backwards compatible transmitted packets continues to be
> send as version 1, but some groundwork has been done to make this a per-link
> property.

Series applied, thanks.

^ permalink raw reply

* Re: [PATCH] r8169: only enable PCI wakeups when WOL is active
From: David Miller @ 2017-10-11 22:26 UTC (permalink / raw)
  To: drake; +Cc: nic_swsd, netdev, romieu, linux
In-Reply-To: <20171011045652.6301-1-drake@endlessm.com>

From: Daniel Drake <drake@endlessm.com>
Date: Wed, 11 Oct 2017 12:56:52 +0800

> rtl_init_one() currently enables PCI wakeups if the ethernet device
> is found to be WOL-capable. There is no need to do this when
> rtl8169_set_wol() will correctly enable or disable the same wakeup flag
> when WOL is activated/deactivated.
> 
> This works around an ACPI DSDT bug which prevents the Acer laptop models
> Aspire ES1-533, Aspire ES1-732, PackardBell ENTE69AP and Gateway NE533
> from entering S3 suspend - even when no ethernet cable is connected.
> 
> On these platforms, the DSDT says that GPE08 is a wakeup source for
> ethernet, but this GPE fires as soon as the system goes into suspend,
> waking the system up immediately. Having the wakeup normally disabled
> avoids this issue in the default case.
> 
> With this change, WOL will continue to be unusable on these platforms
> (it will instantly wake up if WOL is later enabled by the user) but we
> do not expect this to be a commonly used feature on these consumer
> laptops. We have separately determined that WOL works fine without any
> ACPI GPEs enabled during sleep, so a DSDT fix or override would be
> possible to make WOL work.
> 
> Signed-off-by: Daniel Drake <drake@endlessm.com>

Applied, thank you.

^ permalink raw reply

* Re: [PATCH net-next 0/7] Rewrite some existing functionality
From: David Miller @ 2017-10-11 22:25 UTC (permalink / raw)
  To: subashab; +Cc: netdev
In-Reply-To: <20171011.152259.969926721717992984.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Date: Wed, 11 Oct 2017 15:22:59 -0700 (PDT)

> From: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
> Date: Tue, 10 Oct 2017 22:17:29 -0600
> 
>> This series fixes some of the broken rmnet functionality.
>> Bridge mode is re-written and made useable and the muxed_ep is converted to hlist.
>> 
>> Patches 1-5 are cleanups in preparation for these changes.
>> Patch 6 does the hlist conversion.
>> Patch 7 has the implementation of the rmnet bridge mode.
> 
> Series applied, thank you.

Actually, I reverted:

drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c: In function ‘rmnet_rx_handler’:
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c:174:6: warning: ‘rc’ may be used uninitialized in this function [-Wmaybe-uninitialized]
  int rc;
      ^~

Also, the indentation of the switch statement is wrong, the break
statements need to be indented the same as the rest of the code
in their switch statements.

^ permalink raw reply

* Re: [PATCH net-next 0/7] Rewrite some existing functionality
From: David Miller @ 2017-10-11 22:22 UTC (permalink / raw)
  To: subashab; +Cc: netdev
In-Reply-To: <1507695456-17051-1-git-send-email-subashab@codeaurora.org>

From: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Date: Tue, 10 Oct 2017 22:17:29 -0600

> This series fixes some of the broken rmnet functionality.
> Bridge mode is re-written and made useable and the muxed_ep is converted to hlist.
> 
> Patches 1-5 are cleanups in preparation for these changes.
> Patch 6 does the hlist conversion.
> Patch 7 has the implementation of the rmnet bridge mode.

Series applied, thank you.

^ 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