* Re: [PATCH] mlx5: avoid build warnings on 32-bit
From: David Miller @ 2015-01-13 22:08 UTC (permalink / raw)
To: arnd; +Cc: netdev, eli, linux-rdma
In-Reply-To: <4105686.Jz5UR0277i@wuerfel>
From: Arnd Bergmann <arnd@arndb.de>
Date: Tue, 13 Jan 2015 17:08:06 +0100
> The mlx5 driver passes a string pointer in through a 'u64' variable,
> which on 32-bit machines causes a build warning:
>
> drivers/net/ethernet/mellanox/mlx5/core/debugfs.c: In function 'qp_read_field':
> drivers/net/ethernet/mellanox/mlx5/core/debugfs.c:303:11: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
>
> The code is in fact safe, so we can shut up the warning by adding
> extra type casts.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Applied.
^ permalink raw reply
* Re: [PATCH] tcp: Fix RFC reference in comment
From: John Heffner @ 2015-01-13 22:01 UTC (permalink / raw)
To: Banerjee, Debabrata
Cc: Yuchung Cheng, David Miller, netdev, linux-kernel@vger.kernel.org
In-Reply-To: <D0DAFA79.4435F%dbanerje@akamai.com>
On Tue, Jan 13, 2015 at 4:42 PM, Banerjee, Debabrata
<dbanerje@akamai.com> wrote:
> On 1/13/15, 4:36 PM, "Yuchung Cheng" <ycheng@google.com> wrote:
>
>>On Tue, Jan 13, 2015 at 1:10 PM, Debabrata Banerjee <dbanerje@akamai.com>
>>wrote:
>>>
>>> -/* RFC2861. Reset CWND after idle period longer RTO to "restart
>>>window".
>>> +/* RFC2581 4.1. Reset CWND after idle period longer RTO to "restart
>>>window".
>>> * This is the first part of cwnd validation mechanism. */
>>> static void tcp_cwnd_restart(struct sock *sk, const struct dst_entry
>>>*dst)
>>> {
>>
>>RFC2861 resets the cwnd like in RFC2581, but the rest of the code
>>implements RFC2861. So I think the current comment is fine.
>
>
> No RFC2861 is an experimental RFC that's implemented in
> tcp_cwnd_application_limited(). RFC2861 Recommends reducing the cwnd by
> averaging the current cwnd and the used cwnd as the new cwnd.
>
>
> RFC2581 4.1 Says to set cwnd to initial cwnd if more than one rto has
> passed since the last send. This is what is implemented in the function
> above.
Look at the code a little closer -- it's decaying cwnd based on number
of timeouts as described in 2861, not resetting to IW as recommended
in 2581.
-John
^ permalink raw reply
* Re: BW regression after "tcp: refine TSO autosizing"
From: Eric Dumazet @ 2015-01-13 22:00 UTC (permalink / raw)
To: Eyal Perry
Cc: Or Gerlitz, Linux Netdev List, Amir Vadai, Yevgeny Petrilin,
Saeed Mahameed, Ido Shamay, Amir Ancel, Eyal Perry
In-Reply-To: <54B590FB.5040805@dev.mellanox.co.il>
On Tue, 2015-01-13 at 23:41 +0200, Eyal Perry wrote:
> On 1/13/2015 22:21 PM, Or Gerlitz wrote:
> > On Tue, Jan 13, 2015 at 8:57 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> >> On Tue, 2015-01-13 at 18:48 +0200, Eyal Perry wrote:
> >>> Hello Eric,
> >>> Lately we've observed performance degradation in BW of about 30-40% (depends on
> >>> the setup we use).
> >>> I've bisected the issue down to the this commit: 605ad7f1 ("tcp: refine TSO
> >>> autosizing")
> >>>
> >>> For instance, I was running the following test:
> >>> 1. Bounding net device' irqs to core 0 for both client and server side
> >>> 2. Running netperf with 64K massage size (used the following command)
> >>> $ netperf -H remote -T 1,1 -l 100 -t TCP_STREAM -- -k THROUGHPUT -M 65536 -m 65536
> >>>
> >>> I ran the test on upstream net-next including your patch and than reverted it
> >>> and these are the results I got was improvement from 14.6Gbps to 22.1Gbps.
> >>>
> >>> an additional difference I've noticed when inspecting the ethtool statics,
> >>> number of xmit_more packets increased from 4 to 160 with the reverted kernel.
> >>>
> >>> We are investigating this issue, do you have a hint?
> >> Which driver are you using for this test ?
> > AFAIK, mlx4
> Oops, forgot to mention.
> mlx4 indeed.
Make sure you do not drop packets at receiver.
(Patch might have increased raw speed, and receiver starts dropping
packets because it is not able to sustain line rate on a single flow)
If cwnd is too small, then yes, sending slightly smaller TSO packets can
impact performance, but this is desirable as well.
This is a congestion control problem.
lpaa23:~# nstat >/dev/null; DUMP_TCP_INFO=1 ./netperf -H lpaa24;nstat
MIGRATED TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to lpaa24.prod.google.com () port 0 AF_INET
rto=201000 ato=0 pmtu=1500 rcv_ssthresh=29200 rtt=52 rttvar=2 snd_ssthresh=66 cwnd=102 reordering=3 total_retrans=439 ca_state=0
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 17366.51
#kernel
IpInReceives 379010 0.0
IpInDelivers 379010 0.0
IpOutRequests 494794 0.0
IcmpInErrors 1 0.0
IcmpInTimeExcds 1 0.0
IcmpOutErrors 1 0.0
IcmpOutTimeExcds 1 0.0
IcmpMsgInType3 1 0.0
IcmpMsgOutType3 1 0.0
TcpActiveOpens 18 0.0
TcpPassiveOpens 4 0.0
TcpAttemptFails 8 0.0
TcpEstabResets 7 0.0
TcpInSegs 378992 0.0
TcpOutSegs 14993053 0.0
TcpRetransSegs 439 0.0
TcpOutRsts 28 0.0
UdpInDatagrams 16 0.0
UdpNoPorts 1 0.0
UdpOutDatagrams 17 0.0
TcpExtTW 3 0.0
TcpExtDelayedACKs 1 0.0
TcpExtTCPPrequeued 1 0.0
TcpExtTCPHPHits 14 0.0
TcpExtTCPPureAcks 301046 0.0
TcpExtTCPHPAcks 77858 0.0
TcpExtTCPSackRecovery 75 0.0
TcpExtTCPFastRetrans 439 0.0
TcpExtTCPAbortOnData 7 0.0
TcpExtTCPSackShifted 17 0.0
TcpExtTCPSackMerged 57 0.0
TcpExtTCPSackShiftFallback 234 0.0
TcpExtTCPRcvCoalesce 6 0.0
TcpExtTCPFastOpenActive 7 0.0
TcpExtTCPSpuriousRtxHostQueues 2 0.0
TcpExtTCPAutoCorking 68423 0.0
TcpExtTCPOrigDataSent 14992970 0.0
TcpExtTCPHystartTrainDetect 1 0.0
TcpExtTCPHystartTrainCwnd 70 0.0
IpExtInOctets 19731445 0.0
IpExtOutOctets 21736126719 0.0
IpExtInNoECTPkts 379010 0.0
You also can see in this sample Hystart ended slow start
with a very small cwnd of 70
^ permalink raw reply
* Re: [Xen-devel] [PATCH 08/14] xen-netback: use foreign page information from the pages themselves
From: David Miller @ 2015-01-13 21:57 UTC (permalink / raw)
To: david.vrabel; +Cc: xen-devel, boris.ostrovsky, jennifer.herbert, netdev
In-Reply-To: <54B52F1B.8040408@citrix.com>
From: David Vrabel <david.vrabel@citrix.com>
Date: Tue, 13 Jan 2015 14:43:39 +0000
> On 12/01/15 15:43, David Vrabel wrote:
>> From: Jenny Herbert <jenny.herbert@citrix.com>
>>
>> Use the foreign page flag in netback to get the domid and grant ref
>> needed for the grant copy. This signficiantly simplifies the netback
>> code and makes netback work with foreign pages from other backends
>> (e.g., blkback).
>>
>> This allows blkback to use iSCSI disks provided by domUs running on
>> the same host.
>
> Dave,
>
> This depends on several xen changes. It's been Acked-by: Ian Campbell
> <ian.campbell@citrix.com>
>
> Are you happy for me to merge this via the xen tree in 3.20?
No objections from me:
Acked-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* Re: [PATCH] rocker: fix harmless warning on 32-bit machines
From: David Miller @ 2015-01-13 21:56 UTC (permalink / raw)
To: arnd; +Cc: netdev, jiri, sfeldma, linux-arm-kernel
In-Reply-To: <4047824.AYNhYQQ6UI@wuerfel>
From: Arnd Bergmann <arnd@arndb.de>
Date: Tue, 13 Jan 2015 15:23:52 +0100
> The rocker driver tries to assign a pointer to a 64-bit integer
> and then back to a pointer. This is safe on all architectures,
> but causes a compiler warning when pointers are shorter than
> 64-bit:
>
> rocker/rocker.c: In function 'rocker_desc_cookie_ptr_get':
> rocker/rocker.c:809:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> return (void *) desc_info->desc->cookie;
> ^
>
> This adds another cast to uintptr_t to tell the compiler
> that it's safe.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Applied to net-next, thanks.
^ permalink raw reply
* Re: [net PATCH 1/1] drivers: net: cpsw: fix multicast flush in dual emac mode
From: David Miller @ 2015-01-13 21:54 UTC (permalink / raw)
To: mugunthanvnm; +Cc: netdev, stable
In-Reply-To: <1421150749-4329-1-git-send-email-mugunthanvnm@ti.com>
From: Mugunthan V N <mugunthanvnm@ti.com>
Date: Tue, 13 Jan 2015 17:35:49 +0530
> Since ALE table is a common resource for both the interfaces in Dual EMAC
> mode and while bringing up the second interface in cpsw_ndo_set_rx_mode()
> all the multicast entries added by the first interface is flushed out and
> only second interface multicast addresses are added. Fixing this by
> flushing multicast addresses based on dual EMAC port vlans which will not
> affect the other emac port multicast addresses.
>
> Fixes: d9ba8f9 (driver: net: ethernet: cpsw: dual emac interface implementation)
> Cc: <stable@vger.kernel.org> # v3.9+
> Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH net-next] cxgb4: Ripping out old hard-wired initialization code in driver
From: David Miller @ 2015-01-13 21:53 UTC (permalink / raw)
To: hariprasad; +Cc: netdev, leedom, nirranjan
In-Reply-To: <1421142565-10232-1-git-send-email-hariprasad@chelsio.com>
From: Hariprasad Shenai <hariprasad@chelsio.com>
Date: Tue, 13 Jan 2015 15:19:25 +0530
> Removing old hard-wired initialization code in the driver, which is no longer
> used. Also deprecating few module parameters.
>
> Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next] tipc: remove redundant timer defined in tipc_sock struct
From: David Miller @ 2015-01-13 21:46 UTC (permalink / raw)
To: ying.xue
Cc: jon.maloy, Paul.Gortmaker, erik.hugne, ericalp, netdev,
tipc-discussion
In-Reply-To: <1421140068-3614-1-git-send-email-ying.xue@windriver.com>
From: Ying Xue <ying.xue@windriver.com>
Date: Tue, 13 Jan 2015 17:07:48 +0800
> Remove the redundant timer defined in tipc_sock structure, instead we
> can directly reuse the sk_timer defined in sock structure.
>
> Signed-off-by: Ying Xue <ying.xue@windriver.com>
> Acked-by: Erik Hugne <erik.hugne@ericsson.com>
> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com>
Applied, thank you.
^ permalink raw reply
* Re: [PATCH] af_packet: fix typo of "unlikely" conditional in packet_snd
From: John W. Linville @ 2015-01-13 21:40 UTC (permalink / raw)
To: David Miller; +Cc: netdev, dborkman, hannes
In-Reply-To: <20150113.142604.824938958848327187.davem@davemloft.net>
On Tue, Jan 13, 2015 at 02:26:04PM -0500, David Miller wrote:
> From: "John W. Linville" <linville@tuxdriver.com>
> Date: Tue, 13 Jan 2015 14:20:11 -0500
>
> > Change "unlikely(offset) < 0" to "unlikely(offset < 0)"...
> >
> > Coverity: CID 1259984
> >
> > Signed-off-by: John W. Linville <linville@tuxdriver.com>
>
> Should be fixed in the 'net' tree by:
>
> commit 46d2cfb192b30d729aef064808ed5ece47cee369
> Author: Christoph Jaeger <cj@linux.com>
> Date: Sun Jan 11 13:01:16 2015 -0500
>
> packet: bail out of packet_snd() if L2 header creation fails
Cool, sorry for the noise!
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply
* Re: be2net: SR-IOV, vlan isolation issue
From: Greg Rose @ 2015-01-13 21:45 UTC (permalink / raw)
To: Yoann Juet; +Cc: netdev@vger.kernel.org, Yoann Juet
In-Reply-To: <54AF9FF1.3040906@univ-nantes.fr>
On Fri, Jan 9, 2015 at 1:31 AM, Yoann Juet
<veilletechno-irts@univ-nantes.fr> wrote:
> Hi all,
>
> I recently discovered unattended behavior from Emulex cards with KVM
> hypervisor and SR-IOV. On such 10Gbps cards (be2net module, Emulex
> OneConnect OCm14102-U3-D devices), guest machines attached to VFs on the
> Emulex Physical Functions (PF) see all multicast and broadcast (not unicast)
> traffic from/to other VM located on the same PF **BUT** on other vlans. Just
> put into promiscuous mode the guest machine's interface and you will observe
> inbound, outbound (multicast + broadcast only) irrelevant traffic.
>
> Please note that irrelevant traffic is not sent to the guest machine TCP/IP
> stack. No firewall hitting for instance. The issue is about traffic
> monitoring with a VF put into promiscuous mode using a sniffer like tshark,
> tcpdump... Vlan isolation seems not 100% effective from the guest
> perspective since mcast+bcast information leaks.
>
> A similar issue has already been observed with Broadcom cards and then
> patched by the developer team. Refer to the post in archive "bnx2x + SR-IOV,
> no internal L2 switching", 12 Feb 2014. Emulex driver seems to suffer the
> same problem, isn't it ?
>
> Many thanks for considering my request,
> Best regards,
> Yoann Juet
You may want to contact the emulex maintainers listed in the
MAINTAINERS file or else copy them on this email. They may not be
looking at netdev all the time.
>From the MAINTAINERS file:
SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
M: Sathya Perla <sathya.perla@emulex.com>
M: Subbu Seetharaman <subbu.seetharaman@emulex.com>
M: Ajit Khaparde <ajit.khaparde@emulex.com>
Just FYI...
- Greg
>
> ----
>
> # ethtool -i eth2
> driver: be2net
> version: 10.4u
> firmware-version: 10.2.470.14
> bus-info: 0000:04:00.0
> supports-statistics: yes
> supports-test: yes
> supports-eeprom-access: yes
> supports-register-dump: no
> supports-priv-flags: no
>
> #lspci -vv
> ...
> [V1] Vendor specific: Emulex OneConnect OCm14102-U3-D 2-port 10GbE Mezz CNA
> [V2] Vendor specific: OCm14102-U3-D
> ...
>
> # uname -a
> Linux machriemoor.u06.univ-nantes.prive 3.18.1-dsiun-141008 #12 SMP Wed Dec
> 24 11:34:32 CET 2014 x86_64 GNU/Linux
>
> # virsh version
> Compiled against library: libvirt 1.2.9
> Using library: libvirt 1.2.9
> Using API: QEMU 1.2.9
> Running hypervisor: QEMU 2.1.2
>
> I'm using libvirt with <hostdev> XML blocks to assign VF to a particular
> vlan: For instance:
>
> <interface type='network'>
> <mac address='de:ad:ef:ef:f3:01'/>
> <source network='pf-eth2'/>
> <vlan>
> <tag id='888'/>
> </vlan>
> </interface>
>
> ----
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] net/fsl: replace (1 << x) with BIT(x) for bit definitions in xgmac_mdio
From: David Miller @ 2015-01-13 21:44 UTC (permalink / raw)
To: shh.xie; +Cc: netdev, Shaohui.Xie
In-Reply-To: <1421116259-16152-1-git-send-email-shh.xie@gmail.com>
From: <shh.xie@gmail.com>
Date: Tue, 13 Jan 2015 10:30:59 +0800
> From: Shaohui Xie <Shaohui.Xie@freescale.com>
>
> Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Applied.
^ permalink raw reply
* Re: [PATCH] net/fsl: fix a bug in xgmac_mdio
From: David Miller @ 2015-01-13 21:43 UTC (permalink / raw)
To: shh.xie; +Cc: netdev, Shaohui.Xie
In-Reply-To: <1421116231-16100-1-git-send-email-shh.xie@gmail.com>
From: <shh.xie@gmail.com>
Date: Tue, 13 Jan 2015 10:30:31 +0800
> From: Shaohui Xie <Shaohui.Xie@freescale.com>
>
> There is a bug in xgmac_mdio_read when clear the bit MDIO_STAT_ENC,
> which '&' is missed in 'mdio_stat &= ~MDIO_STAT_ENC'.
>
> Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Applied.
^ permalink raw reply
* Re: [PATCH] tcp: Fix RFC reference in comment
From: Banerjee, Debabrata @ 2015-01-13 21:42 UTC (permalink / raw)
To: Yuchung Cheng; +Cc: David Miller, netdev, linux-kernel@vger.kernel.org
In-Reply-To: <CAK6E8=d6NMZjyH1JFoJX_ioAdQNYCAvH-G3ja9fScwW9u2=NFQ@mail.gmail.com>
On 1/13/15, 4:36 PM, "Yuchung Cheng" <ycheng@google.com> wrote:
>On Tue, Jan 13, 2015 at 1:10 PM, Debabrata Banerjee <dbanerje@akamai.com>
>wrote:
>>
>> -/* RFC2861. Reset CWND after idle period longer RTO to "restart
>>window".
>> +/* RFC2581 4.1. Reset CWND after idle period longer RTO to "restart
>>window".
>> * This is the first part of cwnd validation mechanism. */
>> static void tcp_cwnd_restart(struct sock *sk, const struct dst_entry
>>*dst)
>> {
>
>RFC2861 resets the cwnd like in RFC2581, but the rest of the code
>implements RFC2861. So I think the current comment is fine.
No RFC2861 is an experimental RFC that's implemented in
tcp_cwnd_application_limited(). RFC2861 Recommends reducing the cwnd by
averaging the current cwnd and the used cwnd as the new cwnd.
RFC2581 4.1 Says to set cwnd to initial cwnd if more than one rto has
passed since the last send. This is what is implemented in the function
above.
-Debabrata
^ permalink raw reply
* Re: BW regression after "tcp: refine TSO autosizing"
From: Eyal Perry @ 2015-01-13 21:41 UTC (permalink / raw)
To: Or Gerlitz, Eric Dumazet
Cc: Linux Netdev List, Amir Vadai, Yevgeny Petrilin, Saeed Mahameed,
Ido Shamay, Amir Ancel, Eyal Perry
In-Reply-To: <CAJ3xEMibMzJH-AB7pBnO9qBL4McTdsajqHzxXkadnTf1khNdxA@mail.gmail.com>
On 1/13/2015 22:21 PM, Or Gerlitz wrote:
> On Tue, Jan 13, 2015 at 8:57 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
>> On Tue, 2015-01-13 at 18:48 +0200, Eyal Perry wrote:
>>> Hello Eric,
>>> Lately we've observed performance degradation in BW of about 30-40% (depends on
>>> the setup we use).
>>> I've bisected the issue down to the this commit: 605ad7f1 ("tcp: refine TSO
>>> autosizing")
>>>
>>> For instance, I was running the following test:
>>> 1. Bounding net device' irqs to core 0 for both client and server side
>>> 2. Running netperf with 64K massage size (used the following command)
>>> $ netperf -H remote -T 1,1 -l 100 -t TCP_STREAM -- -k THROUGHPUT -M 65536 -m 65536
>>>
>>> I ran the test on upstream net-next including your patch and than reverted it
>>> and these are the results I got was improvement from 14.6Gbps to 22.1Gbps.
>>>
>>> an additional difference I've noticed when inspecting the ethtool statics,
>>> number of xmit_more packets increased from 4 to 160 with the reverted kernel.
>>>
>>> We are investigating this issue, do you have a hint?
>> Which driver are you using for this test ?
> AFAIK, mlx4
Oops, forgot to mention.
mlx4 indeed.
^ permalink raw reply
* [net-next PATCH v2 12/12] net: rocker: implement delete flow routine
From: John Fastabend @ 2015-01-13 21:40 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
drivers/net/ethernet/rocker/rocker.c | 46 +++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index 8acd730..0b400c4 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -4439,7 +4439,51 @@ static int rocker_set_flows(struct net_device *dev,
static int rocker_del_flows(struct net_device *dev,
struct net_flow_rule *flow)
{
- return -EOPNOTSUPP;
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ struct rocker_flow_tbl_entry *entry;
+ struct rocker_group_tbl_entry *group;
+ struct hlist_node *tmp;
+ int bkt, err = -EEXIST;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rocker_port->rocker->flow_tbl_lock, flags);
+ hash_for_each_safe(rocker_port->rocker->flow_tbl,
+ bkt, tmp, entry, entry) {
+ if (rocker_goto_value(flow->table_id) != entry->key.tbl_id ||
+ flow->uid != entry->cookie)
+ continue;
+
+ hash_del(&entry->entry);
+ err = 0;
+ break;
+ }
+ spin_unlock_irqrestore(&rocker_port->rocker->flow_tbl_lock, flags);
+
+ if (!err)
+ goto done;
+
+ spin_lock_irqsave(&rocker_port->rocker->group_tbl_lock, flags);
+ hash_for_each_safe(rocker_port->rocker->group_tbl,
+ bkt, tmp, group, entry) {
+ if (rocker_goto_value(flow->table_id) !=
+ ROCKER_GROUP_TYPE_GET(group->group_id) ||
+ flow->uid != group->cookie)
+ continue;
+
+ hash_del(&group->entry);
+ err = 0;
+ break;
+ }
+ spin_unlock_irqrestore(&rocker_port->rocker->group_tbl_lock, flags);
+
+done:
+ if (!err) {
+ err = rocker_cmd_exec(rocker_port->rocker, rocker_port,
+ rocker_cmd_flow_tbl_del,
+ entry, NULL, NULL, true);
+ kfree(entry);
+ }
+ return err;
}
#endif
^ permalink raw reply related
* [net-next PATCH v2 11/12] net: rocker: have flow api calls set cookie value
From: John Fastabend @ 2015-01-13 21:39 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
drivers/net/ethernet/rocker/rocker.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index 4cbead8..8acd730 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -3891,7 +3891,7 @@ static int rocker_flow_set_ig_port(struct net_device *dev,
in_lport_mask = flow->matches[0].mask_u32;
goto_tbl = rocker_goto_value(flow->actions[0].args[0].value_u16);
- return rocker_flow_tbl_ig_port(rocker_port, flags, 0,
+ return rocker_flow_tbl_ig_port(rocker_port, flags, flow->uid,
in_lport, in_lport_mask,
goto_tbl);
}
@@ -3948,7 +3948,7 @@ static int rocker_flow_set_vlan(struct net_device *dev,
}
}
- return rocker_flow_tbl_vlan(rocker_port, flags, 0, in_lport,
+ return rocker_flow_tbl_vlan(rocker_port, flags, flow->uid, in_lport,
vlan_id, vlan_id_mask, goto_tbl,
untagged, new_vlan_id);
}
@@ -4022,7 +4022,7 @@ static int rocker_flow_set_term_mac(struct net_device *dev,
}
}
- return rocker_flow_tbl_term_mac(rocker_port, 0,
+ return rocker_flow_tbl_term_mac(rocker_port, flow->uid,
in_lport, in_lport_mask,
ethtype, eth_dst, eth_dst_mask,
vlan_id, vlan_id_mask,
@@ -4117,7 +4117,7 @@ static int rocker_flow_set_bridge(struct net_device *dev,
}
/* Ignoring eth_dst_mask it seems to cause a EINVAL return code */
- return rocker_flow_tbl_bridge(rocker_port, flags, 0,
+ return rocker_flow_tbl_bridge(rocker_port, flags, flow->uid,
eth_dst, eth_dst_mask,
vlan_id, tunnel_id,
goto_tbl, group_id, copy_to_cpu);
@@ -4219,7 +4219,7 @@ static int rocker_flow_set_acl(struct net_device *dev,
}
}
- return rocker_flow_tbl_acl(rocker_port, flags, 0,
+ return rocker_flow_tbl_acl(rocker_port, flags, flow->uid,
in_lport, in_lport_mask,
eth_src, eth_src_mask,
eth_dst, eth_dst_mask, ethtype,
@@ -4279,6 +4279,8 @@ static int rocker_flow_set_group_slice_l3_unicast(struct net_device *dev,
}
}
+ entry->cookie = flow->uid;
+
return rocker_group_tbl_do(rocker_port, flags, entry);
}
@@ -4330,6 +4332,8 @@ static int rocker_flow_set_group_slice_l2_rewrite(struct net_device *dev,
}
}
+ entry->cookie = flow->uid;
+
return rocker_group_tbl_do(rocker_port, flags, entry);
}
@@ -4381,6 +4385,8 @@ static int rocker_flow_set_group_slice_l2(struct net_device *dev,
}
}
+ entry->cookie = flow->uid;
+
return rocker_group_tbl_do(rocker_port, flags, entry);
}
^ permalink raw reply related
* Re: [PATCH net-next] bridge: fix uninitialized variable warning
From: David Miller @ 2015-01-13 21:39 UTC (permalink / raw)
To: roopa; +Cc: netdev, tgraf
In-Reply-To: <1421108728-12778-1-git-send-email-roopa@cumulusnetworks.com>
From: roopa@cumulusnetworks.com
Date: Mon, 12 Jan 2015 16:25:28 -0800
> From: Roopa Prabhu <roopa@cumulusnetworks.com>
>
> net/bridge/br_netlink.c: In function ‘br_fill_ifinfo’:
> net/bridge/br_netlink.c:146:32: warning: ‘vid_range_flags’ may be used uninitialized in this function [-Wmaybe-uninitialized]
> err = br_fill_ifvlaninfo_range(skb, vid_range_start,
> ^
> net/bridge/br_netlink.c:108:6: note: ‘vid_range_flags’ was declared here
> u16 vid_range_flags;
>
> Reported-by: Thomas Graf <tgraf@suug.ch>
> Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Applied, thank you.
^ permalink raw reply
* [net-next PATCH v2 10/12] net: rocker: add cookie to group acls and use flow_id to set cookie
From: John Fastabend @ 2015-01-13 21:39 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
Rocker uses a cookie value to identify flows however the flow API
already has a unique id for each flow. To help the translation
add support to set the cookie value through the internal rocker
flow API and then use the unique id in the cases where it is
available.
This patch extends the internal code paths to support the new
cookie value.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
drivers/net/ethernet/rocker/rocker.c | 64 ++++++++++++++++++++++------------
1 file changed, 42 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index de4c58e..4cbead8 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -120,6 +120,7 @@ struct rocker_flow_tbl_entry {
struct rocker_group_tbl_entry {
struct hlist_node entry;
+ u64 cookie;
u32 cmd;
u32 group_id; /* key */
u16 group_count;
@@ -2233,7 +2234,8 @@ static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
kfree(match);
} else {
found = match;
- found->cookie = rocker->flow_tbl_next_cookie++;
+ if (!found->cookie)
+ found->cookie = rocker->flow_tbl_next_cookie++;
hash_add(rocker->flow_tbl, &found->entry, found->key_crc32);
add_to_hw = true;
}
@@ -2311,7 +2313,7 @@ static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
return rocker_flow_tbl_add(rocker_port, entry, nowait);
}
-static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
+static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port, u64 flow_id,
int flags, u32 in_lport, u32 in_lport_mask,
enum rocker_of_dpa_table_id goto_tbl)
{
@@ -2327,11 +2329,14 @@ static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
entry->key.ig_port.in_lport_mask = in_lport_mask;
entry->key.ig_port.goto_tbl = goto_tbl;
+ if (flow_id)
+ entry->cookie = flow_id;
+
return rocker_flow_tbl_do(rocker_port, flags, entry);
}
static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
- int flags, u32 in_lport,
+ int flags, u64 flow_id, u32 in_lport,
__be16 vlan_id, __be16 vlan_id_mask,
enum rocker_of_dpa_table_id goto_tbl,
bool untagged, __be16 new_vlan_id)
@@ -2352,10 +2357,14 @@ static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
entry->key.vlan.untagged = untagged;
entry->key.vlan.new_vlan_id = new_vlan_id;
+ if (flow_id)
+ entry->cookie = flow_id;
+
return rocker_flow_tbl_do(rocker_port, flags, entry);
}
static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
+ u64 flow_id,
u32 in_lport, u32 in_lport_mask,
__be16 eth_type, const u8 *eth_dst,
const u8 *eth_dst_mask, __be16 vlan_id,
@@ -2388,11 +2397,14 @@ static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
entry->key.term_mac.vlan_id_mask = vlan_id_mask;
entry->key.term_mac.copy_to_cpu = copy_to_cpu;
+ if (flow_id)
+ entry->cookie = flow_id;
+
return rocker_flow_tbl_do(rocker_port, flags, entry);
}
static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
- int flags,
+ int flags, u64 flow_id,
const u8 *eth_dst, const u8 *eth_dst_mask,
__be16 vlan_id, u32 tunnel_id,
enum rocker_of_dpa_table_id goto_tbl,
@@ -2442,11 +2454,14 @@ static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
entry->key.bridge.group_id = group_id;
entry->key.bridge.copy_to_cpu = copy_to_cpu;
+ if (flow_id)
+ entry->cookie = flow_id;
+
return rocker_flow_tbl_do(rocker_port, flags, entry);
}
static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
- int flags, u32 in_lport,
+ int flags, u64 flow_id, u32 in_lport,
u32 in_lport_mask,
const u8 *eth_src, const u8 *eth_src_mask,
const u8 *eth_dst, const u8 *eth_dst_mask,
@@ -2494,6 +2509,9 @@ static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
entry->key.acl.ip_tos_mask = ip_tos_mask;
entry->key.acl.group_id = group_id;
+ if (flow_id)
+ entry->cookie = flow_id;
+
return rocker_flow_tbl_do(rocker_port, flags, entry);
}
@@ -2604,7 +2622,7 @@ static int rocker_group_tbl_do(struct rocker_port *rocker_port,
}
static int rocker_group_l2_interface(struct rocker_port *rocker_port,
- int flags, __be16 vlan_id,
+ int flags, int flow_id, __be16 vlan_id,
u32 out_lport, int pop_vlan)
{
struct rocker_group_tbl_entry *entry;
@@ -2615,6 +2633,7 @@ static int rocker_group_l2_interface(struct rocker_port *rocker_port,
entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_lport);
entry->l2_interface.pop_vlan = pop_vlan;
+ entry->cookie = flow_id;
return rocker_group_tbl_do(rocker_port, flags, entry);
}
@@ -2713,7 +2732,7 @@ static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
if (rocker_port->stp_state == BR_STATE_LEARNING ||
rocker_port->stp_state == BR_STATE_FORWARDING) {
out_lport = rocker_port->lport;
- err = rocker_group_l2_interface(rocker_port, flags,
+ err = rocker_group_l2_interface(rocker_port, flags, 0,
vlan_id, out_lport,
pop_vlan);
if (err) {
@@ -2739,7 +2758,7 @@ static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
return 0;
out_lport = 0;
- err = rocker_group_l2_interface(rocker_port, flags,
+ err = rocker_group_l2_interface(rocker_port, flags, 0,
vlan_id, out_lport,
pop_vlan);
if (err) {
@@ -2813,7 +2832,7 @@ static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_lport);
int err;
- err = rocker_flow_tbl_acl(rocker_port, flags,
+ err = rocker_flow_tbl_acl(rocker_port, flags, 0,
in_lport, in_lport_mask,
eth_src, eth_src_mask,
ctrl->eth_dst, ctrl->eth_dst_mask,
@@ -2842,7 +2861,7 @@ static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
if (!rocker_port_is_bridged(rocker_port))
return 0;
- err = rocker_flow_tbl_bridge(rocker_port, flags,
+ err = rocker_flow_tbl_bridge(rocker_port, flags, 0,
ctrl->eth_dst, ctrl->eth_dst_mask,
vlan_id, tunnel_id,
goto_tbl, group_id, ctrl->copy_to_cpu);
@@ -2864,7 +2883,7 @@ static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
if (ntohs(vlan_id) == 0)
vlan_id = rocker_port->internal_vlan_id;
- err = rocker_flow_tbl_term_mac(rocker_port,
+ err = rocker_flow_tbl_term_mac(rocker_port, 0,
rocker_port->lport, in_lport_mask,
ctrl->eth_type, ctrl->eth_dst,
ctrl->eth_dst_mask, vlan_id,
@@ -2978,7 +2997,7 @@ static int rocker_port_vlan(struct rocker_port *rocker_port, int flags,
return err;
}
- err = rocker_flow_tbl_vlan(rocker_port, flags,
+ err = rocker_flow_tbl_vlan(rocker_port, flags, 0,
in_lport, vlan_id, vlan_id_mask,
goto_tbl, untagged, internal_vlan_id);
if (err)
@@ -3003,7 +3022,7 @@ static int rocker_port_ig_tbl(struct rocker_port *rocker_port, int flags)
in_lport_mask = 0xffff0000;
goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN;
- err = rocker_flow_tbl_ig_port(rocker_port, flags,
+ err = rocker_flow_tbl_ig_port(rocker_port, flags, 0,
in_lport, in_lport_mask,
goto_tbl);
if (err)
@@ -3053,7 +3072,7 @@ static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_lport);
if (!(flags & ROCKER_OP_FLAG_REFRESH)) {
- err = rocker_flow_tbl_bridge(rocker_port, flags, addr, NULL,
+ err = rocker_flow_tbl_bridge(rocker_port, flags, 0, addr, NULL,
vlan_id, tunnel_id, goto_tbl,
group_id, copy_to_cpu);
if (err)
@@ -3188,7 +3207,7 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
vlan_id = rocker_port->internal_vlan_id;
eth_type = htons(ETH_P_IP);
- err = rocker_flow_tbl_term_mac(rocker_port,
+ err = rocker_flow_tbl_term_mac(rocker_port, 0,
rocker_port->lport, in_lport_mask,
eth_type, rocker_port->dev->dev_addr,
dst_mac_mask, vlan_id, vlan_id_mask,
@@ -3197,7 +3216,7 @@ static int rocker_port_router_mac(struct rocker_port *rocker_port,
return err;
eth_type = htons(ETH_P_IPV6);
- err = rocker_flow_tbl_term_mac(rocker_port,
+ err = rocker_flow_tbl_term_mac(rocker_port, 0,
rocker_port->lport, in_lport_mask,
eth_type, rocker_port->dev->dev_addr,
dst_mac_mask, vlan_id, vlan_id_mask,
@@ -3232,7 +3251,7 @@ static int rocker_port_fwding(struct rocker_port *rocker_port)
continue;
vlan_id = htons(vid);
pop_vlan = rocker_vlan_id_is_internal(vlan_id);
- err = rocker_group_l2_interface(rocker_port, flags,
+ err = rocker_group_l2_interface(rocker_port, flags, 0,
vlan_id, out_lport,
pop_vlan);
if (err) {
@@ -3872,7 +3891,7 @@ static int rocker_flow_set_ig_port(struct net_device *dev,
in_lport_mask = flow->matches[0].mask_u32;
goto_tbl = rocker_goto_value(flow->actions[0].args[0].value_u16);
- return rocker_flow_tbl_ig_port(rocker_port, flags,
+ return rocker_flow_tbl_ig_port(rocker_port, flags, 0,
in_lport, in_lport_mask,
goto_tbl);
}
@@ -3929,7 +3948,7 @@ static int rocker_flow_set_vlan(struct net_device *dev,
}
}
- return rocker_flow_tbl_vlan(rocker_port, flags, in_lport,
+ return rocker_flow_tbl_vlan(rocker_port, flags, 0, in_lport,
vlan_id, vlan_id_mask, goto_tbl,
untagged, new_vlan_id);
}
@@ -4003,7 +4022,8 @@ static int rocker_flow_set_term_mac(struct net_device *dev,
}
}
- return rocker_flow_tbl_term_mac(rocker_port, in_lport, in_lport_mask,
+ return rocker_flow_tbl_term_mac(rocker_port, 0,
+ in_lport, in_lport_mask,
ethtype, eth_dst, eth_dst_mask,
vlan_id, vlan_id_mask,
copy_to_cpu, flags);
@@ -4097,7 +4117,7 @@ static int rocker_flow_set_bridge(struct net_device *dev,
}
/* Ignoring eth_dst_mask it seems to cause a EINVAL return code */
- return rocker_flow_tbl_bridge(rocker_port, flags,
+ return rocker_flow_tbl_bridge(rocker_port, flags, 0,
eth_dst, eth_dst_mask,
vlan_id, tunnel_id,
goto_tbl, group_id, copy_to_cpu);
@@ -4199,7 +4219,7 @@ static int rocker_flow_set_acl(struct net_device *dev,
}
}
- return rocker_flow_tbl_acl(rocker_port, flags,
+ return rocker_flow_tbl_acl(rocker_port, flags, 0,
in_lport, in_lport_mask,
eth_src, eth_src_mask,
eth_dst, eth_dst_mask, ethtype,
^ permalink raw reply related
* [net-next PATCH v2 09/12] net: rocker: add multicast path to bridging
From: John Fastabend @ 2015-01-13 21:38 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
Add path in table graph to send packets to the bridge table.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
drivers/net/ethernet/rocker/rocker_pipeline.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/net/ethernet/rocker/rocker_pipeline.h b/drivers/net/ethernet/rocker/rocker_pipeline.h
index 6d1e2ee..1a3dcdb 100644
--- a/drivers/net/ethernet/rocker/rocker_pipeline.h
+++ b/drivers/net/ethernet/rocker/rocker_pipeline.h
@@ -511,6 +511,14 @@ struct net_flow_tbl_node rocker_table_node_vlan = {
.jump = rocker_table_node_vlan_next};
struct net_flow_jump_table rocker_table_node_term_mac_next[] = {
+ { .field = {.instance = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_DST_MAC,
+ .mask_type = NFL_MASK_TYPE_LPM,
+ .type = NFL_FIELD_REF_ATTR_TYPE_U64,
+ .value_u64 = (__u64)0x1,
+ .mask_u64 = (__u64)0x1,
+ }, .node = ROCKER_FLOW_TABLE_ID_BRIDGING},
{ .field = {0}, .node = ROCKER_FLOW_TABLE_ID_UNICAST_ROUTING},
{ .field = {0}, .node = 0},
};
^ permalink raw reply related
* Re: [PATCH net-next 2/8] net: dsa: make module builds work
From: David Miller @ 2015-01-13 21:38 UTC (permalink / raw)
To: f.fainelli; +Cc: netdev, buytenh
In-Reply-To: <1421099866-3184-3-git-send-email-f.fainelli@gmail.com>
From: Florian Fainelli <f.fainelli@gmail.com>
Date: Mon, 12 Jan 2015 13:57:40 -0800
> Building any DSA driver as a module will work from a compilation/linking
> perspective, but the resulting modules produced are not functional.
>
> Any DSA driver references register_switch_driver and
> unregister_switch_driver which are provided by net/dsa/dsa.c, so loading
> any of these modules prior to dsa_core.ko being loaded will faill.
>
> Unfortunately, loading dsa_core.ko will make us call dsa_switch_probe()
> which will find no DSA switch driver and return an error so we are stuck
> there because there is no switch driver available. So this is getting us
> nowhere.
>
> This patch introduces a separate module, named dsa_lib which contains
> register_switch_driver, unregister_switch_driver and dsa_switch_probe
> (to avoid exposing the list and mutex used for walking switch drivers),
> such that the following can be done:
>
> - load dsa_lib
> - load the dsa switch driver, e.g: mv88e6060, bcm_sf2
> - load the dsa_core module
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
This looks worse to me.
Really, the match table and probing should not be in dsa_core at all.
It should only be done in individual drivers.
^ permalink raw reply
* [net-next PATCH v2 08/12] net: rocker: add group_id slices and drop explicit goto
From: John Fastabend @ 2015-01-13 21:38 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
This adds the group tables for l3_unicast, l2_rewrite and l2. In
addition to adding the tables we extend the metadata fields to
support three different group id lookups. One for each table and
drop the more generic one previously being used.
Finally we can also drop the goto action as it is not used anymore.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
drivers/net/ethernet/rocker/rocker.c | 174 ++++++++++++++++++++++++
drivers/net/ethernet/rocker/rocker_pipeline.h | 180 ++++++++++++++++++++++---
2 files changed, 328 insertions(+), 26 deletions(-)
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index 08efd8b..de4c58e 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -4088,8 +4088,8 @@ static int rocker_flow_set_bridge(struct net_device *dev,
case ACTION_COPY_TO_CPU:
copy_to_cpu = true;
break;
- case ROCKER_ACTION_SET_GROUP_ID:
- group_id = arg->value_u32;
+ case ROCKER_ACTION_SET_L3_UNICAST_GID:
+ group_id = ROCKER_GROUP_L3_UNICAST(arg->value_u32);
break;
default:
return -EINVAL;
@@ -4188,9 +4188,11 @@ static int rocker_flow_set_acl(struct net_device *dev,
group_id = ROCKER_GROUP_NONE;
for (i = 0; flow->actions && flow->actions[i].uid; i++) {
+ struct net_flow_action_arg *arg = &flow->actions[i].args[0];
+
switch (flow->actions[i].uid) {
- case ROCKER_ACTION_SET_GROUP_ID:
- group_id = flow->actions[i].args[0].value_u32;
+ case ROCKER_ACTION_SET_L3_UNICAST_GID:
+ group_id = ROCKER_GROUP_L3_UNICAST(arg->value_u32);
break;
default:
return -EINVAL;
@@ -4207,6 +4209,161 @@ static int rocker_flow_set_acl(struct net_device *dev,
group_id);
}
+static int rocker_flow_set_group_slice_l3_unicast(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ struct rocker_group_tbl_entry *entry;
+ int i, flags = 0;
+
+ entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ if (!entry)
+ return -ENOMEM;
+
+ for (i = 0; flow->matches && flow->matches[i].instance; i++) {
+ struct net_flow_field_ref *r = &flow->matches[i];
+
+ switch (r->instance) {
+ case ROCKER_HEADER_INSTANCE_L3_UNICAST_GID:
+ entry->group_id = ROCKER_GROUP_L3_UNICAST(r->value_u32);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; flow->actions && flow->actions[i].uid; i++) {
+ struct net_flow_action_arg *arg = &flow->actions[i].args[0];
+
+ switch (flow->actions[i].uid) {
+ case ACTION_SET_ETH_SRC:
+ ether_addr_copy(entry->l3_unicast.eth_src,
+ (u8 *)&arg->value_u64);
+ break;
+ case ACTION_SET_ETH_DST:
+ ether_addr_copy(entry->l3_unicast.eth_dst,
+ (u8 *)&arg->value_u64);
+ break;
+ case ACTION_SET_VLAN_ID:
+ entry->l3_unicast.vlan_id = htons(arg->value_u16);
+ break;
+ case ACTION_CHECK_TTL_DROP:
+ entry->l3_unicast.ttl_check = true;
+ break;
+ case ROCKER_ACTION_SET_L2_REWRITE_GID:
+ entry->l3_unicast.group_id =
+ ROCKER_GROUP_L2_REWRITE(arg->value_u32);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return rocker_group_tbl_do(rocker_port, flags, entry);
+}
+
+static int rocker_flow_set_group_slice_l2_rewrite(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ struct rocker_group_tbl_entry *entry;
+ int i, flags = 0;
+
+ entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ if (!entry)
+ return -ENOMEM;
+
+ for (i = 0; flow->matches && flow->matches[i].instance; i++) {
+ struct net_flow_field_ref *r = &flow->matches[i];
+
+ switch (r->instance) {
+ case ROCKER_HEADER_INSTANCE_L2_REWRITE_GID:
+ entry->group_id = ROCKER_GROUP_L2_REWRITE(r->value_u32);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; flow->actions && flow->actions[i].uid; i++) {
+ struct net_flow_action_arg *arg = &flow->actions[i].args[0];
+
+ switch (flow->actions[i].uid) {
+ case ACTION_SET_ETH_SRC:
+ ether_addr_copy(entry->l2_rewrite.eth_src,
+ (u8 *)&arg->value_u64);
+ break;
+ case ACTION_SET_ETH_DST:
+ ether_addr_copy(entry->l2_rewrite.eth_dst,
+ (u8 *)&arg->value_u64);
+ break;
+ case ACTION_SET_VLAN_ID:
+ entry->l2_rewrite.vlan_id = htons(arg->value_u16);
+ break;
+ case ROCKER_ACTION_SET_L2_GID:
+ entry->l2_rewrite.group_id =
+ ROCKER_GROUP_L2_INTERFACE(arg->value_u32,
+ rocker_port->lport);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return rocker_group_tbl_do(rocker_port, flags, entry);
+}
+
+static int rocker_flow_set_group_slice_l2(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ struct rocker_group_tbl_entry *entry;
+ int i, flags = 0;
+ u32 lport;
+
+ entry = kzalloc(sizeof(*entry), rocker_op_flags_gfp(flags));
+ if (!entry)
+ return -ENOMEM;
+
+ lport = rocker_port->lport;
+
+ /* Use the dev lport if we don't have a specified lport instance
+ * from the user. We need to walk the list once before to extract
+ * any lport attribute.
+ */
+ for (i = 0; flow->matches && flow->matches[i].instance; i++) {
+ switch (flow->matches[i].instance) {
+ case ROCKER_HEADER_METADATA_IN_LPORT:
+ lport = flow->matches[i].value_u32;
+ }
+ }
+
+ for (i = 0; flow->matches && flow->matches[i].instance; i++) {
+ struct net_flow_field_ref *r = &flow->matches[i];
+
+ switch (r->instance) {
+ case ROCKER_HEADER_INSTANCE_L2_GID:
+ entry->group_id =
+ ROCKER_GROUP_L2_INTERFACE(r->value_u32, lport);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; flow->actions && flow->actions[i].uid; i++) {
+ switch (flow->actions[i].uid) {
+ case ACTION_POP_VLAN:
+ entry->l2_interface.pop_vlan = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return rocker_group_tbl_do(rocker_port, flags, entry);
+}
+
static int rocker_set_flows(struct net_device *dev,
struct net_flow_rule *flow)
{
@@ -4237,6 +4394,15 @@ static int rocker_set_flows(struct net_device *dev,
case ROCKER_FLOW_TABLE_ID_ACL_POLICY:
err = rocker_flow_set_acl(dev, flow);
break;
+ case ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L3_UNICAST:
+ err = rocker_flow_set_group_slice_l3_unicast(dev, flow);
+ break;
+ case ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2_REWRITE:
+ err = rocker_flow_set_group_slice_l2_rewrite(dev, flow);
+ break;
+ case ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2:
+ err = rocker_flow_set_group_slice_l2(dev, flow);
+ break;
default:
break;
}
diff --git a/drivers/net/ethernet/rocker/rocker_pipeline.h b/drivers/net/ethernet/rocker/rocker_pipeline.h
index 7136380..6d1e2ee 100644
--- a/drivers/net/ethernet/rocker/rocker_pipeline.h
+++ b/drivers/net/ethernet/rocker/rocker_pipeline.h
@@ -22,19 +22,23 @@ enum rocker_header_ids {
enum rocker_header_metadata_fields {
ROCKER_HEADER_METADATA_UNSPEC,
ROCKER_HEADER_METADATA_IN_LPORT,
- ROCKER_HEADER_METADATA_GOTO_TBL,
- ROCKER_HEADER_METADATA_GROUP_ID,
+ ROCKER_HEADER_METADATA_L3_UNICAST_GID,
+ ROCKER_HEADER_METADATA_L2_REWRITE_GID,
+ ROCKER_HEADER_METADATA_L2_GID,
};
struct net_flow_field rocker_metadata_fields[] = {
{ .name = "in_lport",
.uid = ROCKER_HEADER_METADATA_IN_LPORT,
.bitwidth = 32,},
- { .name = "goto_tbl",
- .uid = ROCKER_HEADER_METADATA_GOTO_TBL,
- .bitwidth = 16,},
- { .name = "group_id",
- .uid = ROCKER_HEADER_METADATA_GROUP_ID,
+ { .name = "l3_unicast_group_id",
+ .uid = ROCKER_HEADER_METADATA_L3_UNICAST_GID,
+ .bitwidth = 32,},
+ { .name = "l2_rewrite_group_id",
+ .uid = ROCKER_HEADER_METADATA_L2_REWRITE_GID,
+ .bitwidth = 32,},
+ { .name = "l2_group_id",
+ .uid = ROCKER_HEADER_METADATA_L2_GID,
.bitwidth = 32,},
};
@@ -68,22 +72,39 @@ struct net_flow_action_arg rocker_set_group_id_args[] = {
enum rocker_action_ids {
ROCKER_ACTION_UNSPEC = ACTION_MAX_UID,
- ROCKER_ACTION_SET_GROUP_ID,
+ ROCKER_ACTION_SET_L3_UNICAST_GID,
+ ROCKER_ACTION_SET_L2_REWRITE_GID,
+ ROCKER_ACTION_SET_L2_GID,
+};
+
+struct net_flow_action rocker_set_l3_unicast_group_id = {
+ .name = "set_l3_unicast_group_id",
+ .uid = ROCKER_ACTION_SET_L3_UNICAST_GID,
+ .args = rocker_set_group_id_args,
+};
+
+struct net_flow_action rocker_set_l2_rewrite_group_id = {
+ .name = "set_l2_rewrite_group_id",
+ .uid = ROCKER_ACTION_SET_L2_REWRITE_GID,
+ .args = rocker_set_group_id_args,
};
-struct net_flow_action rocker_set_group_id = {
- .name = "set_group_id",
- .uid = ROCKER_ACTION_SET_GROUP_ID,
+struct net_flow_action rocker_set_l2_group_id = {
+ .name = "set_l2_group_id",
+ .uid = ROCKER_ACTION_SET_L2_GID,
.args = rocker_set_group_id_args,
};
struct net_flow_action *rocker_action_list[] = {
&net_flow_set_vlan_id,
&net_flow_copy_to_cpu,
- &rocker_set_group_id,
+ &rocker_set_l3_unicast_group_id,
+ &rocker_set_l2_rewrite_group_id,
+ &rocker_set_l2_group_id,
&net_flow_pop_vlan,
&net_flow_set_eth_src,
&net_flow_set_eth_dst,
+ &net_flow_check_ttl_drop,
NULL,
};
@@ -94,8 +115,9 @@ enum rocker_header_instance_ids {
ROCKER_HEADER_INSTANCE_VLAN_OUTER,
ROCKER_HEADER_INSTANCE_IPV4,
ROCKER_HEADER_INSTANCE_IN_LPORT,
- ROCKER_HEADER_INSTANCE_GOTO_TABLE,
- ROCKER_HEADER_INSTANCE_GROUP_ID,
+ ROCKER_HEADER_INSTANCE_L3_UNICAST_GID,
+ ROCKER_HEADER_INSTANCE_L2_REWRITE_GID,
+ ROCKER_HEADER_INSTANCE_L2_GID,
};
struct net_flow_jump_table rocker_parse_ethernet[] = {
@@ -183,9 +205,23 @@ struct net_flow_hdr_node rocker_in_lport_header_node = {
.jump = rocker_terminal_headers,
};
-struct net_flow_hdr_node rocker_group_id_header_node = {
- .name = "group_id",
- .uid = ROCKER_HEADER_INSTANCE_GROUP_ID,
+struct net_flow_hdr_node rocker_l2_group_id_header_node = {
+ .name = "l2_group_id",
+ .uid = ROCKER_HEADER_INSTANCE_L2_GID,
+ .hdrs = rocker_metadata_headers,
+ .jump = rocker_terminal_headers,
+};
+
+struct net_flow_hdr_node rocker_l2_rewrite_group_id_header_node = {
+ .name = "l2_rewrite_group_id",
+ .uid = ROCKER_HEADER_INSTANCE_L2_REWRITE_GID,
+ .hdrs = rocker_metadata_headers,
+ .jump = rocker_terminal_headers,
+};
+
+struct net_flow_hdr_node rocker_l3_unicast_group_id_header_node = {
+ .name = "l3_uniscast_group_id",
+ .uid = ROCKER_HEADER_INSTANCE_L3_UNICAST_GID,
.hdrs = rocker_metadata_headers,
.jump = rocker_terminal_headers,
};
@@ -195,7 +231,9 @@ struct net_flow_hdr_node *rocker_header_nodes[] = {
&rocker_vlan_header_node,
&rocker_ipv4_header_node,
&rocker_in_lport_header_node,
- &rocker_group_id_header_node,
+ &rocker_l3_unicast_group_id_header_node,
+ &rocker_l2_rewrite_group_id_header_node,
+ &rocker_l2_group_id_header_node,
NULL,
};
@@ -296,13 +334,48 @@ struct net_flow_field_ref rocker_matches_acl[] = {
{ .instance = 0, .field = 0},
};
+struct net_flow_field_ref rocker_matches_l3_unicast_group_slice[2] = {
+ { .instance = ROCKER_HEADER_INSTANCE_L3_UNICAST_GID,
+ .header = ROCKER_HEADER_METADATA,
+ .field = ROCKER_HEADER_METADATA_L3_UNICAST_GID,
+ .mask_type = NFL_MASK_TYPE_EXACT},
+ { .instance = 0, .field = 0},
+};
+
+struct net_flow_field_ref rocker_matches_l2_rewrite_group_slice[2] = {
+ { .instance = ROCKER_HEADER_INSTANCE_L2_REWRITE_GID,
+ .header = ROCKER_HEADER_METADATA,
+ .field = ROCKER_HEADER_METADATA_L2_REWRITE_GID,
+ .mask_type = NFL_MASK_TYPE_EXACT},
+ { .instance = 0, .field = 0},
+};
+
+struct net_flow_field_ref rocker_matches_l2_group_slice[2] = {
+ { .instance = ROCKER_HEADER_INSTANCE_L2_GID,
+ .header = ROCKER_HEADER_METADATA,
+ .field = ROCKER_HEADER_METADATA_L2_GID,
+ .mask_type = NFL_MASK_TYPE_EXACT},
+ { .instance = 0, .field = 0},
+};
+
int rocker_actions_ig_port[] = {0};
int rocker_actions_vlan[] = {ACTION_SET_VLAN_ID, 0};
int rocker_actions_term_mac[] = {ACTION_COPY_TO_CPU, 0};
-int rocker_actions_ucast_routing[] = {ROCKER_ACTION_SET_GROUP_ID, 0};
-int rocker_actions_bridge[] = {ROCKER_ACTION_SET_GROUP_ID,
+int rocker_actions_ucast_routing[] = {ROCKER_ACTION_SET_L3_UNICAST_GID, 0};
+int rocker_actions_bridge[] = {ROCKER_ACTION_SET_L3_UNICAST_GID,
ACTION_COPY_TO_CPU, 0};
-int rocker_actions_acl[] = {ROCKER_ACTION_SET_GROUP_ID, 0};
+int rocker_actions_acl[] = {ROCKER_ACTION_SET_L3_UNICAST_GID, 0};
+int rocker_actions_group_slice_l3_unicast[] = {ACTION_SET_ETH_SRC,
+ ACTION_SET_ETH_DST,
+ ACTION_SET_VLAN_ID,
+ ROCKER_ACTION_SET_L2_REWRITE_GID,
+ ACTION_CHECK_TTL_DROP, 0};
+int rocker_actions_group_slice_l2_rewrite[] = {ACTION_SET_ETH_SRC,
+ ACTION_SET_ETH_DST,
+ ACTION_SET_VLAN_ID,
+ ROCKER_ACTION_SET_L2_GID,
+ 0};
+int rocker_actions_group_slice_l2[] = {ACTION_POP_VLAN, 0};
enum rocker_flow_table_id_space {
ROCKER_FLOW_TABLE_NULL,
@@ -313,6 +386,9 @@ enum rocker_flow_table_id_space {
ROCKER_FLOW_TABLE_ID_MULTICAST_ROUTING,
ROCKER_FLOW_TABLE_ID_BRIDGING,
ROCKER_FLOW_TABLE_ID_ACL_POLICY,
+ ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L3_UNICAST,
+ ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2_REWRITE,
+ ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2,
};
struct net_flow_tbl rocker_ingress_port_table = {
@@ -375,6 +451,33 @@ struct net_flow_tbl rocker_acl_table = {
.cache = {0},
};
+struct net_flow_tbl rocker_group_slice_l3_unicast_table = {
+ .name = "group_slice_l3_unicast",
+ .uid = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L3_UNICAST,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_l3_unicast_group_slice,
+ .actions = rocker_actions_group_slice_l3_unicast,
+};
+
+struct net_flow_tbl rocker_group_slice_l2_rewrite_table = {
+ .name = "group_slice_l2_rewrite",
+ .uid = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2_REWRITE,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_l2_rewrite_group_slice,
+ .actions = rocker_actions_group_slice_l2_rewrite,
+};
+
+struct net_flow_tbl rocker_group_slice_l2_table = {
+ .name = "group_slice_l2",
+ .uid = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_l2_group_slice,
+ .actions = rocker_actions_group_slice_l2,
+};
+
struct net_flow_tbl *rocker_table_list[] = {
&rocker_ingress_port_table,
&rocker_vlan_table,
@@ -382,6 +485,9 @@ struct net_flow_tbl *rocker_table_list[] = {
&rocker_ucast_routing_table,
&rocker_bridge_table,
&rocker_acl_table,
+ &rocker_group_slice_l3_unicast_table,
+ &rocker_group_slice_l2_rewrite_table,
+ &rocker_group_slice_l2_table,
NULL,
};
@@ -432,6 +538,7 @@ struct net_flow_tbl_node rocker_table_node_ucast_routing = {
.jump = rocker_table_node_ucast_routing_next};
struct net_flow_jump_table rocker_table_node_acl_next[] = {
+ { .field = {0}, .node = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L3_UNICAST},
{ .field = {0}, .node = 0},
};
@@ -439,6 +546,32 @@ struct net_flow_tbl_node rocker_table_node_acl = {
.uid = ROCKER_FLOW_TABLE_ID_ACL_POLICY,
.jump = rocker_table_node_acl_next};
+struct net_flow_jump_table rocker_table_node_group_l3_unicast_next[1] = {
+ { .field = {0}, .node = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2_REWRITE},
+};
+
+struct net_flow_tbl_node rocker_table_node_group_l3_unicast = {
+ .uid = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L3_UNICAST,
+ .jump = rocker_table_node_group_l3_unicast_next};
+
+struct net_flow_jump_table rocker_table_node_group_l2_rewrite_next[1] = {
+ { .field = {0}, .node = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2},
+};
+
+struct net_flow_tbl_node rocker_table_node_group_l2_rewrite = {
+ .uid = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2_REWRITE,
+ .jump = rocker_table_node_group_l2_rewrite_next};
+
+struct net_flow_jump_table rocker_table_node_group_l2_next[1] = {
+ { .field = {0}, .node = 0},
+};
+
+struct net_flow_tbl_node rocker_table_node_group_l2 = {
+ .uid = ROCKER_FLOW_TABLE_ID_GROUP_SLICE_L2,
+ .jump = rocker_table_node_group_l2_next};
+
+struct net_flow_tbl_node rocker_table_node_nil = {.uid = 0, .jump = NULL};
+
struct net_flow_tbl_node *rocker_table_nodes[] = {
&rocker_table_node_ingress_port,
&rocker_table_node_vlan,
@@ -446,6 +579,9 @@ struct net_flow_tbl_node *rocker_table_nodes[] = {
&rocker_table_node_ucast_routing,
&rocker_table_node_bridge,
&rocker_table_node_acl,
- NULL,
+ &rocker_table_node_group_l3_unicast,
+ &rocker_table_node_group_l2_rewrite,
+ &rocker_table_node_group_l2,
+ NULL
};
#endif /*_ROCKER_PIPELINE_H_*/
^ permalink raw reply related
* [net-next PATCH v2 07/12] net: rocker: add set flow rules
From: John Fastabend @ 2015-01-13 21:38 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
Implement set flow operations for existing rocker tables.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
drivers/net/ethernet/rocker/rocker.c | 422 ++++++++++++++++++++++++++++++++++
1 file changed, 422 insertions(+)
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index d2ea451..08efd8b 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -3830,6 +3830,425 @@ static struct net_flow_hdr_node **rocker_get_hgraph(struct net_device *d)
{
return rocker_header_nodes;
}
+
+static u32 rocker_goto_value(u32 id)
+{
+ switch (id) {
+ case ROCKER_FLOW_TABLE_ID_INGRESS_PORT:
+ return ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
+ case ROCKER_FLOW_TABLE_ID_VLAN:
+ return ROCKER_OF_DPA_TABLE_ID_VLAN;
+ case ROCKER_FLOW_TABLE_ID_TERMINATION_MAC:
+ return ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
+ case ROCKER_FLOW_TABLE_ID_UNICAST_ROUTING:
+ return ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
+ case ROCKER_FLOW_TABLE_ID_MULTICAST_ROUTING:
+ return ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
+ case ROCKER_FLOW_TABLE_ID_BRIDGING:
+ return ROCKER_OF_DPA_TABLE_ID_BRIDGING;
+ case ROCKER_FLOW_TABLE_ID_ACL_POLICY:
+ return ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+ default:
+ return 0;
+ }
+}
+
+static int rocker_flow_set_ig_port(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ enum rocker_of_dpa_table_id goto_tbl;
+ u32 in_lport_mask, in_lport;
+ int flags = 0;
+
+ /* ingress port table only supports one field/mask/action this
+ * simplifies the key construction and we can assume the values
+ * are the correct types/mask/action by valid check above. The
+ * user could pass multiple match/actions in a message with the
+ * same field multiple times currently the valid test does not
+ * catch this and we just use the first specified.
+ */
+ in_lport = flow->matches[0].value_u32;
+ in_lport_mask = flow->matches[0].mask_u32;
+ goto_tbl = rocker_goto_value(flow->actions[0].args[0].value_u16);
+
+ return rocker_flow_tbl_ig_port(rocker_port, flags,
+ in_lport, in_lport_mask,
+ goto_tbl);
+}
+
+static int rocker_flow_set_vlan(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ __be16 vlan_id, vlan_id_mask, new_vlan_id;
+ bool untagged, have_in_lport = false;
+ enum rocker_of_dpa_table_id goto_tbl;
+ int i, flags = 0;
+ u32 in_lport;
+
+ goto_tbl = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
+
+ /* If user does not specify vid match default to any */
+ vlan_id = htons(1);
+ vlan_id_mask = 0;
+
+ for (i = 0; flow->matches && flow->matches[i].instance; i++) {
+ switch (flow->matches[i].instance) {
+ case ROCKER_HEADER_INSTANCE_IN_LPORT:
+ in_lport = flow->matches[i].value_u32;
+ have_in_lport = true;
+ break;
+ case ROCKER_HEADER_INSTANCE_VLAN_OUTER:
+ if (flow->matches[i].field != HEADER_VLAN_VID)
+ break;
+
+ vlan_id = htons(flow->matches[i].value_u16);
+ vlan_id_mask = htons(flow->matches[i].mask_u16);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (!have_in_lport)
+ return -EINVAL;
+
+ /* If user does not specify a new vlan id use default vlan id */
+ new_vlan_id = rocker_port_vid_to_vlan(rocker_port, vlan_id, &untagged);
+
+ for (i = 0; flow->actions && flow->actions[i].uid; i++) {
+ struct net_flow_action_arg *arg = &flow->actions[i].args[0];
+
+ switch (flow->actions[i].uid) {
+ case ACTION_SET_VLAN_ID:
+ new_vlan_id = htons(arg->value_u16);
+ if (new_vlan_id)
+ untagged = false;
+ break;
+ }
+ }
+
+ return rocker_flow_tbl_vlan(rocker_port, flags, in_lport,
+ vlan_id, vlan_id_mask, goto_tbl,
+ untagged, new_vlan_id);
+}
+
+static int rocker_flow_set_term_mac(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ __be16 vlan_id, vlan_id_mask, ethtype = 0;
+ const u8 *eth_dst, *eth_dst_mask;
+ u32 in_lport, in_lport_mask;
+ int i, flags = 0;
+ bool copy_to_cpu;
+
+ /* If user does not specify vid match default to any */
+ vlan_id = rocker_port->internal_vlan_id;
+ vlan_id_mask = 0;
+
+ /* If user does not specify in_lport match default to any */
+ in_lport = rocker_port->lport;
+ in_lport_mask = 0;
+
+ /* If user does not specify a mac address match any */
+ eth_dst = rocker_port->dev->dev_addr;
+ eth_dst_mask = zero_mac;
+
+ for (i = 0; flow->matches && flow->matches[i].instance; i++) {
+ switch (flow->matches[i].instance) {
+ case ROCKER_HEADER_INSTANCE_IN_LPORT:
+ in_lport = flow->matches[i].value_u32;
+ in_lport_mask = flow->matches[i].mask_u32;
+ break;
+ case ROCKER_HEADER_INSTANCE_VLAN_OUTER:
+ if (flow->matches[i].field != HEADER_VLAN_VID)
+ break;
+
+ vlan_id = htons(flow->matches[i].value_u16);
+ vlan_id_mask = htons(flow->matches[i].mask_u16);
+ break;
+ case ROCKER_HEADER_INSTANCE_ETHERNET:
+ switch (flow->matches[i].field) {
+ case HEADER_ETHERNET_DST_MAC:
+ eth_dst = (u8 *)&flow->matches[i].value_u64;
+ eth_dst_mask = (u8 *)&flow->matches[i].mask_u64;
+ break;
+ case HEADER_ETHERNET_ETHERTYPE:
+ ethtype = htons(flow->matches[i].value_u16);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (!ethtype)
+ return -EINVAL;
+
+ /* By default do not copy to cpu */
+ copy_to_cpu = false;
+
+ for (i = 0; flow->actions && flow->actions[i].uid; i++) {
+ switch (flow->actions[i].uid) {
+ case ACTION_COPY_TO_CPU:
+ copy_to_cpu = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return rocker_flow_tbl_term_mac(rocker_port, in_lport, in_lport_mask,
+ ethtype, eth_dst, eth_dst_mask,
+ vlan_id, vlan_id_mask,
+ copy_to_cpu, flags);
+}
+
+static int rocker_flow_set_ucast_routing(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ return -EOPNOTSUPP;
+}
+
+static int rocker_flow_set_mcast_routing(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ return -EOPNOTSUPP;
+}
+
+static int rocker_flow_set_bridge(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ enum rocker_of_dpa_table_id goto_tbl;
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ u32 in_lport, in_lport_mask, group_id, tunnel_id;
+ __be16 vlan_id, vlan_id_mask;
+ const u8 *eth_dst, *eth_dst_mask;
+ int i, flags = 0;
+ bool copy_to_cpu;
+
+ goto_tbl = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+
+ /* If user does not specify vid match default to any */
+ vlan_id = rocker_port->internal_vlan_id;
+ vlan_id_mask = 0;
+
+ /* If user does not specify in_lport match default to any */
+ in_lport = rocker_port->lport;
+ in_lport_mask = 0;
+
+ /* If user does not specify a mac address match any */
+ eth_dst = rocker_port->dev->dev_addr;
+ eth_dst_mask = NULL;
+
+ /* Do not support for tunnel_id yet. */
+ tunnel_id = 0;
+
+ for (i = 0; flow->matches && flow->matches[i].instance; i++) {
+ switch (flow->matches[i].instance) {
+ case ROCKER_HEADER_INSTANCE_IN_LPORT:
+ in_lport = flow->matches[i].value_u32;
+ in_lport_mask = flow->matches[i].mask_u32;
+ break;
+ case ROCKER_HEADER_INSTANCE_VLAN_OUTER:
+ if (flow->matches[i].field != HEADER_VLAN_VID)
+ break;
+
+ vlan_id = htons(flow->matches[i].value_u16);
+ vlan_id_mask = htons(flow->matches[i].mask_u16);
+ break;
+ case ROCKER_HEADER_INSTANCE_ETHERNET:
+ switch (flow->matches[i].field) {
+ case HEADER_ETHERNET_DST_MAC:
+ eth_dst = (u8 *)&flow->matches[i].value_u64;
+ eth_dst_mask = (u8 *)&flow->matches[i].mask_u64;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ /* By default do not copy to cpu and skip group assignment */
+ copy_to_cpu = false;
+ group_id = ROCKER_GROUP_NONE;
+
+ for (i = 0; flow->actions && flow->actions[i].uid; i++) {
+ struct net_flow_action_arg *arg = &flow->actions[i].args[0];
+
+ switch (flow->actions[i].uid) {
+ case ACTION_COPY_TO_CPU:
+ copy_to_cpu = true;
+ break;
+ case ROCKER_ACTION_SET_GROUP_ID:
+ group_id = arg->value_u32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ /* Ignoring eth_dst_mask it seems to cause a EINVAL return code */
+ return rocker_flow_tbl_bridge(rocker_port, flags,
+ eth_dst, eth_dst_mask,
+ vlan_id, tunnel_id,
+ goto_tbl, group_id, copy_to_cpu);
+}
+
+static int rocker_flow_set_acl(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ struct rocker_port *rocker_port = netdev_priv(dev);
+ u32 in_lport, in_lport_mask, group_id, tunnel_id;
+ __be16 vlan_id, vlan_id_mask, ethtype = 0;
+ const u8 *eth_dst, *eth_src, *eth_dst_mask, *eth_src_mask;
+ u8 protocol, protocol_mask, dscp, dscp_mask;
+ int i, flags = 0;
+
+ /* If user does not specify vid match default to any */
+ vlan_id = rocker_port->internal_vlan_id;
+ vlan_id_mask = 0;
+
+ /* If user does not specify in_lport match default to any */
+ in_lport = rocker_port->lport;
+ in_lport_mask = 0;
+
+ /* If user does not specify a mac address match any */
+ eth_dst = rocker_port->dev->dev_addr;
+ eth_src = zero_mac;
+ eth_dst_mask = NULL;
+ eth_src_mask = NULL;
+
+ /* If user does not set protocol/dscp mask them out */
+ protocol = 0;
+ dscp = 0;
+ protocol_mask = 0;
+ dscp_mask = 0;
+
+ /* Do not support for tunnel_id yet. */
+ tunnel_id = 0;
+
+ for (i = 0; flow->matches && flow->matches[i].instance; i++) {
+ switch (flow->matches[i].instance) {
+ case ROCKER_HEADER_INSTANCE_IN_LPORT:
+ in_lport = flow->matches[i].value_u32;
+ in_lport_mask = flow->matches[i].mask_u32;
+ break;
+ case ROCKER_HEADER_INSTANCE_VLAN_OUTER:
+ if (flow->matches[i].field != HEADER_VLAN_VID)
+ break;
+
+ vlan_id = htons(flow->matches[i].value_u16);
+ vlan_id_mask = htons(flow->matches[i].mask_u16);
+ break;
+ case ROCKER_HEADER_INSTANCE_ETHERNET:
+ switch (flow->matches[i].field) {
+ case HEADER_ETHERNET_SRC_MAC:
+ eth_src = (u8 *)&flow->matches[i].value_u64;
+ eth_src_mask = (u8 *)&flow->matches[i].mask_u64;
+ break;
+ case HEADER_ETHERNET_DST_MAC:
+ eth_dst = (u8 *)&flow->matches[i].value_u64;
+ eth_dst_mask = (u8 *)&flow->matches[i].mask_u64;
+ break;
+ case HEADER_ETHERNET_ETHERTYPE:
+ ethtype = htons(flow->matches[i].value_u16);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case ROCKER_HEADER_INSTANCE_IPV4:
+ switch (flow->matches[i].field) {
+ case HEADER_IPV4_PROTOCOL:
+ protocol = flow->matches[i].value_u8;
+ protocol_mask = flow->matches[i].mask_u8;
+ break;
+ case HEADER_IPV4_DSCP:
+ dscp = flow->matches[i].value_u8;
+ dscp_mask = flow->matches[i].mask_u8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+ }
+
+ /* By default do not copy to cpu and skip group assignment */
+ group_id = ROCKER_GROUP_NONE;
+
+ for (i = 0; flow->actions && flow->actions[i].uid; i++) {
+ switch (flow->actions[i].uid) {
+ case ROCKER_ACTION_SET_GROUP_ID:
+ group_id = flow->actions[i].args[0].value_u32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return rocker_flow_tbl_acl(rocker_port, flags,
+ in_lport, in_lport_mask,
+ eth_src, eth_src_mask,
+ eth_dst, eth_dst_mask, ethtype,
+ vlan_id, vlan_id_mask,
+ protocol, protocol_mask,
+ dscp, dscp_mask,
+ group_id);
+}
+
+static int rocker_set_flows(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ int err = -EINVAL;
+
+ if (!flow->matches || !flow->actions)
+ return -EINVAL;
+
+ switch (flow->table_id) {
+ case ROCKER_FLOW_TABLE_ID_INGRESS_PORT:
+ err = rocker_flow_set_ig_port(dev, flow);
+ break;
+ case ROCKER_FLOW_TABLE_ID_VLAN:
+ err = rocker_flow_set_vlan(dev, flow);
+ break;
+ case ROCKER_FLOW_TABLE_ID_TERMINATION_MAC:
+ err = rocker_flow_set_term_mac(dev, flow);
+ break;
+ case ROCKER_FLOW_TABLE_ID_UNICAST_ROUTING:
+ err = rocker_flow_set_ucast_routing(dev, flow);
+ break;
+ case ROCKER_FLOW_TABLE_ID_MULTICAST_ROUTING:
+ err = rocker_flow_set_mcast_routing(dev, flow);
+ break;
+ case ROCKER_FLOW_TABLE_ID_BRIDGING:
+ err = rocker_flow_set_bridge(dev, flow);
+ break;
+ case ROCKER_FLOW_TABLE_ID_ACL_POLICY:
+ err = rocker_flow_set_acl(dev, flow);
+ break;
+ default:
+ break;
+ }
+
+ return err;
+}
+
+static int rocker_del_flows(struct net_device *dev,
+ struct net_flow_rule *flow)
+{
+ return -EOPNOTSUPP;
+}
#endif
static const struct net_device_ops rocker_port_netdev_ops = {
@@ -3852,6 +4271,9 @@ static const struct net_device_ops rocker_port_netdev_ops = {
.ndo_flow_get_actions = rocker_get_actions,
.ndo_flow_get_tbl_graph = rocker_get_tgraph,
.ndo_flow_get_hdr_graph = rocker_get_hgraph,
+
+ .ndo_flow_set_rule = rocker_set_flows,
+ .ndo_flow_del_rule = rocker_del_flows,
#endif
};
^ permalink raw reply related
* [net-next PATCH v2 06/12] net: rocker: add pipeline model for rocker switch
From: John Fastabend @ 2015-01-13 21:37 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
This adds rocker support for the net_flow_get_* operations. With this
we can interrogate rocker.
Here we see that for static configurations enabling the get operations
is simply a matter of defining a pipeline model and returning the
structures for the core infrastructure to encapsulate into netlink
messages.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
drivers/net/ethernet/rocker/rocker.c | 65 ++++
drivers/net/ethernet/rocker/rocker_pipeline.h | 451 +++++++++++++++++++++++++
2 files changed, 516 insertions(+)
create mode 100644 drivers/net/ethernet/rocker/rocker_pipeline.h
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index 2f398fa..d2ea451 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -36,6 +36,7 @@
#include <generated/utsrelease.h>
#include "rocker.h"
+#include "rocker_pipeline.h"
static const char rocker_driver_name[] = "rocker";
@@ -3781,6 +3782,56 @@ static int rocker_port_switch_port_stp_update(struct net_device *dev, u8 state)
return rocker_port_stp_update(rocker_port, state);
}
+static void rocker_destroy_flow_tables(struct rocker_port *rocker_port)
+{
+ int i;
+
+ for (i = 0; rocker_table_list[i]; i++)
+ net_flow_destroy_cache(rocker_table_list[i]);
+}
+
+static int rocker_init_flow_tables(struct rocker_port *rocker_port)
+{
+ int i, err;
+
+ for (i = 0; rocker_table_list[i]; i++) {
+ err = net_flow_init_cache(rocker_table_list[i]);
+ if (err) {
+ rocker_destroy_flow_tables(rocker_port);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_FLOW_TABLES
+static struct net_flow_tbl **rocker_get_tables(struct net_device *d)
+{
+ return rocker_table_list;
+}
+
+static struct net_flow_hdr **rocker_get_headers(struct net_device *d)
+{
+ return rocker_header_list;
+}
+
+static struct net_flow_action **rocker_get_actions(struct net_device *d)
+{
+ return rocker_action_list;
+}
+
+static struct net_flow_tbl_node **rocker_get_tgraph(struct net_device *d)
+{
+ return rocker_table_nodes;
+}
+
+static struct net_flow_hdr_node **rocker_get_hgraph(struct net_device *d)
+{
+ return rocker_header_nodes;
+}
+#endif
+
static const struct net_device_ops rocker_port_netdev_ops = {
.ndo_open = rocker_port_open,
.ndo_stop = rocker_port_stop,
@@ -3795,6 +3846,13 @@ static const struct net_device_ops rocker_port_netdev_ops = {
.ndo_bridge_getlink = rocker_port_bridge_getlink,
.ndo_switch_parent_id_get = rocker_port_switch_parent_id_get,
.ndo_switch_port_stp_update = rocker_port_switch_port_stp_update,
+#ifdef CONFIG_NET_FLOW_TABLES
+ .ndo_flow_get_tbls = rocker_get_tables,
+ .ndo_flow_get_hdrs = rocker_get_headers,
+ .ndo_flow_get_actions = rocker_get_actions,
+ .ndo_flow_get_tbl_graph = rocker_get_tgraph,
+ .ndo_flow_get_hdr_graph = rocker_get_hgraph,
+#endif
};
/********************
@@ -3960,6 +4018,7 @@ static void rocker_remove_ports(struct rocker *rocker)
rocker_port = rocker->ports[i];
rocker_port_ig_tbl(rocker_port, ROCKER_OP_FLAG_REMOVE);
unregister_netdev(rocker_port->dev);
+ rocker_destroy_flow_tables(rocker_port);
}
kfree(rocker->ports);
}
@@ -4023,6 +4082,12 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
goto err_port_ig_tbl;
}
+ err = rocker_init_flow_tables(rocker_port);
+ if (err) {
+ dev_err(&pdev->dev, "install flow table failed\n");
+ goto err_port_ig_tbl;
+ }
+
return 0;
err_port_ig_tbl:
diff --git a/drivers/net/ethernet/rocker/rocker_pipeline.h b/drivers/net/ethernet/rocker/rocker_pipeline.h
new file mode 100644
index 0000000..7136380
--- /dev/null
+++ b/drivers/net/ethernet/rocker/rocker_pipeline.h
@@ -0,0 +1,451 @@
+/*
+ * drivers/net/ethernet/rocker/rocker_pipeline.h - Rocker switch device driver
+ * Copyright (c) 2014 John Fastabend <john.r.fastabend@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _ROCKER_PIPELINE_H_
+#define _ROCKER_PIPELINE_H_
+
+#include <linux/if_flow.h>
+#include <linux/if_flow_common.h>
+
+enum rocker_header_ids {
+ ROCKER_HEADER_UNSPEC = HEADER_MAX_UID,
+ ROCKER_HEADER_METADATA,
+};
+
+enum rocker_header_metadata_fields {
+ ROCKER_HEADER_METADATA_UNSPEC,
+ ROCKER_HEADER_METADATA_IN_LPORT,
+ ROCKER_HEADER_METADATA_GOTO_TBL,
+ ROCKER_HEADER_METADATA_GROUP_ID,
+};
+
+struct net_flow_field rocker_metadata_fields[] = {
+ { .name = "in_lport",
+ .uid = ROCKER_HEADER_METADATA_IN_LPORT,
+ .bitwidth = 32,},
+ { .name = "goto_tbl",
+ .uid = ROCKER_HEADER_METADATA_GOTO_TBL,
+ .bitwidth = 16,},
+ { .name = "group_id",
+ .uid = ROCKER_HEADER_METADATA_GROUP_ID,
+ .bitwidth = 32,},
+};
+
+struct net_flow_hdr rocker_metadata_t = {
+ .name = "metadata_t",
+ .uid = ROCKER_HEADER_METADATA,
+ .field_sz = ARRAY_SIZE(rocker_metadata_fields),
+ .fields = rocker_metadata_fields,
+};
+
+struct net_flow_hdr *rocker_header_list[] = {
+ &net_flow_ethernet,
+ &net_flow_vlan,
+ &net_flow_ipv4,
+ &rocker_metadata_t,
+ NULL,
+};
+
+/* rocker specific action definitions */
+struct net_flow_action_arg rocker_set_group_id_args[] = {
+ {
+ .name = "group_id",
+ .type = NFL_ACTION_ARG_TYPE_U32,
+ .value_u32 = 0,
+ },
+ {
+ .name = "",
+ .type = NFL_ACTION_ARG_TYPE_NULL,
+ },
+};
+
+enum rocker_action_ids {
+ ROCKER_ACTION_UNSPEC = ACTION_MAX_UID,
+ ROCKER_ACTION_SET_GROUP_ID,
+};
+
+struct net_flow_action rocker_set_group_id = {
+ .name = "set_group_id",
+ .uid = ROCKER_ACTION_SET_GROUP_ID,
+ .args = rocker_set_group_id_args,
+};
+
+struct net_flow_action *rocker_action_list[] = {
+ &net_flow_set_vlan_id,
+ &net_flow_copy_to_cpu,
+ &rocker_set_group_id,
+ &net_flow_pop_vlan,
+ &net_flow_set_eth_src,
+ &net_flow_set_eth_dst,
+ NULL,
+};
+
+/* headers graph */
+enum rocker_header_instance_ids {
+ ROCKER_HEADER_INSTANCE_UNSPEC,
+ ROCKER_HEADER_INSTANCE_ETHERNET,
+ ROCKER_HEADER_INSTANCE_VLAN_OUTER,
+ ROCKER_HEADER_INSTANCE_IPV4,
+ ROCKER_HEADER_INSTANCE_IN_LPORT,
+ ROCKER_HEADER_INSTANCE_GOTO_TABLE,
+ ROCKER_HEADER_INSTANCE_GROUP_ID,
+};
+
+struct net_flow_jump_table rocker_parse_ethernet[] = {
+ {
+ .field = {
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_ETHERTYPE,
+ .type = NFL_FIELD_REF_ATTR_TYPE_U16,
+ .value_u16 = ETH_P_IP,
+ },
+ .node = ROCKER_HEADER_INSTANCE_IPV4,
+ },
+ {
+ .field = {
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_ETHERTYPE,
+ .type = NFL_FIELD_REF_ATTR_TYPE_U16,
+ .value_u16 = ETH_P_8021Q,
+ },
+ .node = ROCKER_HEADER_INSTANCE_VLAN_OUTER,
+ },
+ {
+ .field = {0},
+ .node = 0,
+ },
+};
+
+int rocker_ethernet_headers[] = {HEADER_ETHERNET, 0};
+
+struct net_flow_hdr_node rocker_ethernet_header_node = {
+ .name = "ethernet",
+ .uid = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .hdrs = rocker_ethernet_headers,
+ .jump = rocker_parse_ethernet,
+};
+
+struct net_flow_jump_table rocker_parse_vlan[] = {
+ {
+ .field = {
+ .header = HEADER_VLAN,
+ .field = HEADER_VLAN_ETHERTYPE,
+ .type = NFL_FIELD_REF_ATTR_TYPE_U16,
+ .value_u16 = ETH_P_IP,
+ },
+ .node = ROCKER_HEADER_INSTANCE_IPV4,
+ },
+ {
+ .field = {0},
+ .node = 0,
+ },
+};
+
+int rocker_vlan_headers[] = {HEADER_VLAN, 0};
+struct net_flow_hdr_node rocker_vlan_header_node = {
+ .name = "vlan",
+ .uid = ROCKER_HEADER_INSTANCE_VLAN_OUTER,
+ .hdrs = rocker_vlan_headers,
+ .jump = rocker_parse_vlan,
+};
+
+struct net_flow_jump_table rocker_terminal_headers[] = {
+ {
+ .field = {0},
+ .node = NFL_JUMP_TABLE_DONE,
+ },
+ {
+ .field = {0},
+ .node = 0,
+ },
+};
+
+int rocker_ipv4_headers[] = {HEADER_IPV4, 0};
+struct net_flow_hdr_node rocker_ipv4_header_node = {
+ .name = "ipv4",
+ .uid = ROCKER_HEADER_INSTANCE_IPV4,
+ .hdrs = rocker_ipv4_headers,
+ .jump = rocker_terminal_headers,
+};
+
+int rocker_metadata_headers[] = {ROCKER_HEADER_METADATA, 0};
+struct net_flow_hdr_node rocker_in_lport_header_node = {
+ .name = "in_lport",
+ .uid = ROCKER_HEADER_INSTANCE_IN_LPORT,
+ .hdrs = rocker_metadata_headers,
+ .jump = rocker_terminal_headers,
+};
+
+struct net_flow_hdr_node rocker_group_id_header_node = {
+ .name = "group_id",
+ .uid = ROCKER_HEADER_INSTANCE_GROUP_ID,
+ .hdrs = rocker_metadata_headers,
+ .jump = rocker_terminal_headers,
+};
+
+struct net_flow_hdr_node *rocker_header_nodes[] = {
+ &rocker_ethernet_header_node,
+ &rocker_vlan_header_node,
+ &rocker_ipv4_header_node,
+ &rocker_in_lport_header_node,
+ &rocker_group_id_header_node,
+ NULL,
+};
+
+/* table definition */
+struct net_flow_field_ref rocker_matches_ig_port[] = {
+ { .instance = ROCKER_HEADER_INSTANCE_IN_LPORT,
+ .header = ROCKER_HEADER_METADATA,
+ .field = ROCKER_HEADER_METADATA_IN_LPORT,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = 0, .field = 0},
+};
+
+struct net_flow_field_ref rocker_matches_vlan[] = {
+ { .instance = ROCKER_HEADER_INSTANCE_IN_LPORT,
+ .header = ROCKER_HEADER_METADATA,
+ .field = ROCKER_HEADER_METADATA_IN_LPORT,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_VLAN_OUTER,
+ .header = HEADER_VLAN,
+ .field = HEADER_VLAN_VID,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = 0, .field = 0},
+};
+
+struct net_flow_field_ref rocker_matches_term_mac[] = {
+ { .instance = ROCKER_HEADER_INSTANCE_IN_LPORT,
+ .header = ROCKER_HEADER_METADATA,
+ .field = ROCKER_HEADER_METADATA_IN_LPORT,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_ETHERTYPE,
+ .mask_type = NFL_MASK_TYPE_EXACT},
+ { .instance = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_DST_MAC,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_VLAN_OUTER,
+ .header = HEADER_VLAN,
+ .field = HEADER_VLAN_VID,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = 0, .field = 0},
+};
+
+struct net_flow_field_ref rocker_matches_ucast_routing[] = {
+ { .instance = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_ETHERTYPE,
+ .mask_type = NFL_MASK_TYPE_EXACT},
+ { .instance = ROCKER_HEADER_INSTANCE_IPV4,
+ .header = HEADER_IPV4,
+ .field = HEADER_IPV4_DST_IP,
+ .mask_type = NFL_MASK_TYPE_LPM},
+ { .instance = 0, .field = 0},
+};
+
+struct net_flow_field_ref rocker_matches_bridge[] = {
+ { .instance = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_DST_MAC,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_VLAN_OUTER,
+ .header = HEADER_VLAN,
+ .field = HEADER_VLAN_VID,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = 0, .field = 0},
+};
+
+struct net_flow_field_ref rocker_matches_acl[] = {
+ { .instance = ROCKER_HEADER_INSTANCE_IN_LPORT,
+ .header = ROCKER_HEADER_METADATA,
+ .field = ROCKER_HEADER_METADATA_IN_LPORT,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_SRC_MAC,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_DST_MAC,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_ETHERNET,
+ .header = HEADER_ETHERNET,
+ .field = HEADER_ETHERNET_ETHERTYPE,
+ .mask_type = NFL_MASK_TYPE_EXACT},
+ { .instance = ROCKER_HEADER_INSTANCE_VLAN_OUTER,
+ .header = HEADER_VLAN,
+ .field = HEADER_VLAN_VID,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_IPV4,
+ .header = HEADER_IPV4,
+ .field = HEADER_IPV4_PROTOCOL,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = ROCKER_HEADER_INSTANCE_IPV4,
+ .header = HEADER_IPV4,
+ .field = HEADER_IPV4_DSCP,
+ .mask_type = NFL_MASK_TYPE_MASK},
+ { .instance = 0, .field = 0},
+};
+
+int rocker_actions_ig_port[] = {0};
+int rocker_actions_vlan[] = {ACTION_SET_VLAN_ID, 0};
+int rocker_actions_term_mac[] = {ACTION_COPY_TO_CPU, 0};
+int rocker_actions_ucast_routing[] = {ROCKER_ACTION_SET_GROUP_ID, 0};
+int rocker_actions_bridge[] = {ROCKER_ACTION_SET_GROUP_ID,
+ ACTION_COPY_TO_CPU, 0};
+int rocker_actions_acl[] = {ROCKER_ACTION_SET_GROUP_ID, 0};
+
+enum rocker_flow_table_id_space {
+ ROCKER_FLOW_TABLE_NULL,
+ ROCKER_FLOW_TABLE_ID_INGRESS_PORT,
+ ROCKER_FLOW_TABLE_ID_VLAN,
+ ROCKER_FLOW_TABLE_ID_TERMINATION_MAC,
+ ROCKER_FLOW_TABLE_ID_UNICAST_ROUTING,
+ ROCKER_FLOW_TABLE_ID_MULTICAST_ROUTING,
+ ROCKER_FLOW_TABLE_ID_BRIDGING,
+ ROCKER_FLOW_TABLE_ID_ACL_POLICY,
+};
+
+struct net_flow_tbl rocker_ingress_port_table = {
+ .name = "ingress_port",
+ .uid = ROCKER_FLOW_TABLE_ID_INGRESS_PORT,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_ig_port,
+ .actions = rocker_actions_ig_port,
+ .cache = {0},
+};
+
+struct net_flow_tbl rocker_vlan_table = {
+ .name = "vlan",
+ .uid = ROCKER_FLOW_TABLE_ID_VLAN,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_vlan,
+ .actions = rocker_actions_vlan,
+ .cache = {0},
+};
+
+struct net_flow_tbl rocker_term_mac_table = {
+ .name = "term_mac",
+ .uid = ROCKER_FLOW_TABLE_ID_TERMINATION_MAC,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_term_mac,
+ .actions = rocker_actions_term_mac,
+ .cache = {0},
+};
+
+struct net_flow_tbl rocker_ucast_routing_table = {
+ .name = "ucast_routing",
+ .uid = ROCKER_FLOW_TABLE_ID_UNICAST_ROUTING,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_ucast_routing,
+ .actions = rocker_actions_ucast_routing,
+ .cache = {0},
+};
+
+struct net_flow_tbl rocker_bridge_table = {
+ .name = "bridge",
+ .uid = ROCKER_FLOW_TABLE_ID_BRIDGING,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_bridge,
+ .actions = rocker_actions_bridge,
+ .cache = {0},
+};
+
+struct net_flow_tbl rocker_acl_table = {
+ .name = "acl",
+ .uid = ROCKER_FLOW_TABLE_ID_ACL_POLICY,
+ .source = 1,
+ .size = -1,
+ .matches = rocker_matches_acl,
+ .actions = rocker_actions_acl,
+ .cache = {0},
+};
+
+struct net_flow_tbl *rocker_table_list[] = {
+ &rocker_ingress_port_table,
+ &rocker_vlan_table,
+ &rocker_term_mac_table,
+ &rocker_ucast_routing_table,
+ &rocker_bridge_table,
+ &rocker_acl_table,
+ NULL,
+};
+
+/* Define the table graph layout */
+struct net_flow_jump_table rocker_table_node_ig_port_next[] = {
+ { .field = {0}, .node = ROCKER_FLOW_TABLE_ID_VLAN},
+ { .field = {0}, .node = 0},
+};
+
+struct net_flow_tbl_node rocker_table_node_ingress_port = {
+ .uid = ROCKER_FLOW_TABLE_ID_INGRESS_PORT,
+ .jump = rocker_table_node_ig_port_next};
+
+struct net_flow_jump_table rocker_table_node_vlan_next[] = {
+ { .field = {0}, .node = ROCKER_FLOW_TABLE_ID_TERMINATION_MAC},
+ { .field = {0}, .node = 0},
+};
+
+struct net_flow_tbl_node rocker_table_node_vlan = {
+ .uid = ROCKER_FLOW_TABLE_ID_VLAN,
+ .jump = rocker_table_node_vlan_next};
+
+struct net_flow_jump_table rocker_table_node_term_mac_next[] = {
+ { .field = {0}, .node = ROCKER_FLOW_TABLE_ID_UNICAST_ROUTING},
+ { .field = {0}, .node = 0},
+};
+
+struct net_flow_tbl_node rocker_table_node_term_mac = {
+ .uid = ROCKER_FLOW_TABLE_ID_TERMINATION_MAC,
+ .jump = rocker_table_node_term_mac_next};
+
+struct net_flow_jump_table rocker_table_node_bridge_next[] = {
+ { .field = {0}, .node = ROCKER_FLOW_TABLE_ID_ACL_POLICY},
+ { .field = {0}, .node = 0},
+};
+
+struct net_flow_tbl_node rocker_table_node_bridge = {
+ .uid = ROCKER_FLOW_TABLE_ID_BRIDGING,
+ .jump = rocker_table_node_bridge_next};
+
+struct net_flow_jump_table rocker_table_node_ucast_routing_next[] = {
+ { .field = {0}, .node = ROCKER_FLOW_TABLE_ID_ACL_POLICY},
+ { .field = {0}, .node = 0},
+};
+
+struct net_flow_tbl_node rocker_table_node_ucast_routing = {
+ .uid = ROCKER_FLOW_TABLE_ID_UNICAST_ROUTING,
+ .jump = rocker_table_node_ucast_routing_next};
+
+struct net_flow_jump_table rocker_table_node_acl_next[] = {
+ { .field = {0}, .node = 0},
+};
+
+struct net_flow_tbl_node rocker_table_node_acl = {
+ .uid = ROCKER_FLOW_TABLE_ID_ACL_POLICY,
+ .jump = rocker_table_node_acl_next};
+
+struct net_flow_tbl_node *rocker_table_nodes[] = {
+ &rocker_table_node_ingress_port,
+ &rocker_table_node_vlan,
+ &rocker_table_node_term_mac,
+ &rocker_table_node_ucast_routing,
+ &rocker_table_node_bridge,
+ &rocker_table_node_acl,
+ NULL,
+};
+#endif /*_ROCKER_PIPELINE_H_*/
^ permalink raw reply related
* [net-next PATCH v2 05/12] net: flow_table: add validation functions for flows
From: John Fastabend @ 2015-01-13 21:37 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
This adds common validation functions that is used before
adding flows to verify they match the table spec returned
from driver.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
net/core/flow_table.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/net/core/flow_table.c b/net/core/flow_table.c
index baeae64..a938929 100644
--- a/net/core/flow_table.c
+++ b/net/core/flow_table.c
@@ -1627,6 +1627,78 @@ static int net_flow_del_rule_cache(struct net_flow_tbl *table,
return -EEXIST;
}
+static int net_flow_is_valid_action_arg(struct net_flow_action *a, int id)
+{
+ struct net_flow_action_arg *args = a->args;
+ int i;
+
+ /* Actions may not have any arguments */
+ if (!a->args)
+ return 0;
+
+ for (i = 0; args[i].type != NFL_ACTION_ARG_TYPE_NULL; i++) {
+ if (a->args[i].type == NFL_ACTION_ARG_TYPE_NULL ||
+ args[i].type != a->args[i].type)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int net_flow_is_valid_action(struct net_flow_action *a, int *actions)
+{
+ int i;
+
+ for (i = 0; actions[i]; i++) {
+ if (actions[i] == a->uid)
+ return net_flow_is_valid_action_arg(a, a->uid);
+ }
+ return -EINVAL;
+}
+
+static int net_flow_is_valid_match(struct net_flow_field_ref *f,
+ struct net_flow_field_ref *fields)
+{
+ int i;
+
+ for (i = 0; fields[i].header; i++) {
+ if (f->header == fields[i].header &&
+ f->field == fields[i].field)
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int net_flow_is_valid_rule(struct net_flow_tbl *table,
+ struct net_flow_rule *flow)
+{
+ struct net_flow_field_ref *fields = table->matches;
+ int *actions = table->actions;
+ int i, err;
+
+ /* Only accept flows with matches AND actions it does not seem
+ * correct to allow a match without actions or action chains
+ * that will never be hit
+ */
+ if (!flow->actions || !flow->matches)
+ return -EINVAL;
+
+ for (i = 0; flow->actions[i].uid; i++) {
+ err = net_flow_is_valid_action(&flow->actions[i], actions);
+ if (err)
+ return -EINVAL;
+ }
+
+ for (i = 0; flow->matches[i].header; i++) {
+ err = net_flow_is_valid_match(&flow->matches[i], fields);
+ if (err)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int net_flow_table_cmd_flows(struct sk_buff *recv_skb,
struct genl_info *info)
{
@@ -1695,6 +1767,9 @@ static int net_flow_table_cmd_flows(struct sk_buff *recv_skb,
switch (cmd) {
case NFL_TABLE_CMD_SET_FLOWS:
+ err = net_flow_is_valid_rule(table, this);
+ if (err)
+ break;
err = dev->netdev_ops->ndo_flow_set_rule(dev, this);
if (!err)
net_flow_add_rule_cache(table, this);
^ permalink raw reply related
* [net-next PATCH v2 04/12] net: flow_table: create a set of common headers and actions
From: John Fastabend @ 2015-01-13 21:36 UTC (permalink / raw)
To: tgraf, simon.horman, sfeldma; +Cc: netdev, gerlitz.or, jhs, andy, davem
In-Reply-To: <20150113212941.13874.48692.stgit@nitbit.x32>
This adds common headers and actions that drivers can use.
I have not yet moved the header graphs into the common header
because I'm not entirely convinced its re-usable. The devices
I have been looking at have different enough header graphs that
they wouldn't be re-usable. However possibly many 40Gbp NICs
for example could share a common header graph. When we get
multiple implementations we can move this into the common file
if it makes sense.
And table structures seem to be unique enough that there is
little value in putting each devices table layout into the
common file so its left for device specific implementation.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
include/linux/if_flow_common.h | 257 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 257 insertions(+)
create mode 100644 include/linux/if_flow_common.h
diff --git a/include/linux/if_flow_common.h b/include/linux/if_flow_common.h
new file mode 100644
index 0000000..d4dd749
--- /dev/null
+++ b/include/linux/if_flow_common.h
@@ -0,0 +1,257 @@
+#ifndef _IF_FLOW_COMMON_H_
+#define _IF_FLOW_COMMON_H_
+
+#include <linux/if_flow.h>
+
+/* Common header definition this section provides a set of common or
+ * standard headers that device driver writers may use to simplify the
+ * driver creation. We do not want vendor or driver specific headers
+ * here though. Driver authors can keep these contained to their driver
+ *
+ * Driver authors may use unique IDs greater than HEADER_MAX_UID it is
+ * guaranteed to be larger than any unique IDs used here.
+ */
+#define HEADER_MAX_UID 100
+
+enum net_flow_headers {
+ HEADER_UNSPEC,
+ HEADER_ETHERNET,
+ HEADER_VLAN,
+ HEADER_IPV4,
+};
+
+enum net_flow_ethernet_fields_ids {
+ HEADER_ETHERNET_UNSPEC,
+ HEADER_ETHERNET_SRC_MAC,
+ HEADER_ETHERNET_DST_MAC,
+ HEADER_ETHERNET_ETHERTYPE,
+};
+
+struct net_flow_field net_flow_ethernet_fields[] = {
+ { .name = "src_mac", .uid = HEADER_ETHERNET_SRC_MAC, .bitwidth = 48},
+ { .name = "dst_mac", .uid = HEADER_ETHERNET_DST_MAC, .bitwidth = 48},
+ { .name = "ethertype",
+ .uid = HEADER_ETHERNET_ETHERTYPE,
+ .bitwidth = 16},
+};
+
+struct net_flow_hdr net_flow_ethernet = {
+ .name = "ethernet",
+ .uid = HEADER_ETHERNET,
+ .field_sz = ARRAY_SIZE(net_flow_ethernet_fields),
+ .fields = net_flow_ethernet_fields,
+};
+
+enum net_flow_vlan_fields_ids {
+ HEADER_VLAN_UNSPEC,
+ HEADER_VLAN_PCP,
+ HEADER_VLAN_CFI,
+ HEADER_VLAN_VID,
+ HEADER_VLAN_ETHERTYPE,
+};
+
+struct net_flow_field net_flow_vlan_fields[] = {
+ { .name = "pcp", .uid = HEADER_VLAN_PCP, .bitwidth = 3,},
+ { .name = "cfi", .uid = HEADER_VLAN_CFI, .bitwidth = 1,},
+ { .name = "vid", .uid = HEADER_VLAN_VID, .bitwidth = 12,},
+ { .name = "ethertype", .uid = HEADER_VLAN_ETHERTYPE, .bitwidth = 16,},
+};
+
+struct net_flow_hdr net_flow_vlan = {
+ .name = "vlan",
+ .uid = HEADER_VLAN,
+ .field_sz = ARRAY_SIZE(net_flow_vlan_fields),
+ .fields = net_flow_vlan_fields,
+};
+
+enum net_flow_ipv4_fields_ids {
+ HEADER_IPV4_UNSPEC,
+ HEADER_IPV4_VERSION,
+ HEADER_IPV4_IHL,
+ HEADER_IPV4_DSCP,
+ HEADER_IPV4_ECN,
+ HEADER_IPV4_LENGTH,
+ HEADER_IPV4_IDENTIFICATION,
+ HEADER_IPV4_FLAGS,
+ HEADER_IPV4_FRAGMENT_OFFSET,
+ HEADER_IPV4_TTL,
+ HEADER_IPV4_PROTOCOL,
+ HEADER_IPV4_CSUM,
+ HEADER_IPV4_SRC_IP,
+ HEADER_IPV4_DST_IP,
+ HEADER_IPV4_OPTIONS,
+};
+
+struct net_flow_field net_flow_ipv4_fields[14] = {
+ { .name = "version",
+ .uid = HEADER_IPV4_VERSION,
+ .bitwidth = 4,},
+ { .name = "ihl",
+ .uid = HEADER_IPV4_IHL,
+ .bitwidth = 4,},
+ { .name = "dscp",
+ .uid = HEADER_IPV4_DSCP,
+ .bitwidth = 6,},
+ { .name = "ecn",
+ .uid = HEADER_IPV4_ECN,
+ .bitwidth = 2,},
+ { .name = "length",
+ .uid = HEADER_IPV4_LENGTH,
+ .bitwidth = 8,},
+ { .name = "identification",
+ .uid = HEADER_IPV4_IDENTIFICATION,
+ .bitwidth = 8,},
+ { .name = "flags",
+ .uid = HEADER_IPV4_FLAGS,
+ .bitwidth = 3,},
+ { .name = "fragment_offset",
+ .uid = HEADER_IPV4_FRAGMENT_OFFSET,
+ .bitwidth = 13,},
+ { .name = "ttl",
+ .uid = HEADER_IPV4_TTL,
+ .bitwidth = 1,},
+ { .name = "protocol",
+ .uid = HEADER_IPV4_PROTOCOL,
+ .bitwidth = 8,},
+ { .name = "csum",
+ .uid = HEADER_IPV4_CSUM,
+ .bitwidth = 8,},
+ { .name = "src_ip",
+ .uid = HEADER_IPV4_SRC_IP,
+ .bitwidth = 32,},
+ { .name = "dst_ip",
+ .uid = HEADER_IPV4_DST_IP,
+ .bitwidth = 32,},
+ { .name = "options",
+ .uid = HEADER_IPV4_OPTIONS,
+ .bitwidth = -1,},
+};
+
+struct net_flow_hdr net_flow_ipv4 = {
+ .name = "ipv4",
+ .uid = HEADER_IPV4,
+ .field_sz = ARRAY_SIZE(net_flow_ipv4_fields),
+ .fields = net_flow_ipv4_fields,
+};
+
+/* Common set of actions. Below are the list of actions that are or we expect
+ * are common enough to be supported by multiple devices.
+ *
+ * Driver authors may use unique IDs greater than ACTION_MAX_UID it is
+ * guaranteed to be larger than any unique IDs used here.
+ */
+#define ACTION_MAX_UID 100
+
+enum net_flow_action_ids {
+ ACTION_SET_UNSPEC,
+ ACTION_SET_VLAN_ID,
+ ACTION_COPY_TO_CPU,
+ ACTION_POP_VLAN,
+ ACTION_SET_ETH_SRC,
+ ACTION_SET_ETH_DST,
+ ACTION_SET_OUT_PORT,
+ ACTION_CHECK_TTL_DROP,
+};
+
+struct net_flow_action_arg net_flow_null_args[1] = {
+ {
+ .name = "",
+ .type = NFL_ACTION_ARG_TYPE_NULL,
+ },
+};
+
+struct net_flow_action net_flow_null_action = {
+ .name = "", .uid = 0, .args = NULL,
+};
+
+struct net_flow_action_arg net_flow_set_vlan_id_args[2] = {
+ {
+ .name = "vlan_id",
+ .type = NFL_ACTION_ARG_TYPE_U16,
+ .value_u16 = 0,
+ },
+ {
+ .name = "",
+ .type = NFL_ACTION_ARG_TYPE_NULL,
+ },
+};
+
+struct net_flow_action net_flow_set_vlan_id = {
+ .name = "set_vlan_id",
+ .uid = ACTION_SET_VLAN_ID,
+ .args = net_flow_set_vlan_id_args,
+};
+
+struct net_flow_action net_flow_copy_to_cpu = {
+ .name = "copy_to_cpu",
+ .uid = ACTION_COPY_TO_CPU,
+ .args = net_flow_null_args,
+};
+
+struct net_flow_action net_flow_pop_vlan = {
+ .name = "pop_vlan",
+ .uid = ACTION_POP_VLAN,
+ .args = net_flow_null_args,
+};
+
+struct net_flow_action_arg net_flow_set_eth_src_args[2] = {
+ {
+ .name = "eth_src",
+ .type = NFL_ACTION_ARG_TYPE_U64,
+ .value_u64 = 0,
+ },
+ {
+ .name = "",
+ .type = NFL_ACTION_ARG_TYPE_NULL,
+ },
+};
+
+struct net_flow_action net_flow_set_eth_src = {
+ .name = "set_eth_src",
+ .uid = ACTION_SET_ETH_SRC,
+ .args = net_flow_set_eth_src_args,
+};
+
+struct net_flow_action_arg net_flow_set_eth_dst_args[2] = {
+ {
+ .name = "eth_dst",
+ .type = NFL_ACTION_ARG_TYPE_U64,
+ .value_u64 = 0,
+ },
+ {
+ .name = "",
+ .type = NFL_ACTION_ARG_TYPE_NULL,
+ },
+};
+
+struct net_flow_action net_flow_set_eth_dst = {
+ .name = "set_eth_dst",
+ .uid = ACTION_SET_ETH_DST,
+ .args = net_flow_set_eth_dst_args,
+};
+
+struct net_flow_action_arg net_flow_set_out_port_args[2] = {
+ {
+ .name = "set_out_port",
+ .type = NFL_ACTION_ARG_TYPE_U32,
+ .value_u32 = 0,
+ },
+ {
+ .name = "",
+ .type = NFL_ACTION_ARG_TYPE_NULL,
+ },
+};
+
+struct net_flow_action net_flow_set_out_port = {
+ .name = "set_out_port",
+ .uid = ACTION_SET_OUT_PORT,
+ .args = net_flow_set_out_port_args,
+};
+
+struct net_flow_action net_flow_check_ttl_drop = {
+ .name = "check_ttl_drop",
+ .uid = ACTION_CHECK_TTL_DROP,
+ .args = net_flow_null_args,
+};
+
+#endif
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox