Commit bc31c905 authored by Willem de Bruijn's avatar Willem de Bruijn Committed by David S. Miller

net-tc: convert tc_from to tc_from_ingress and tc_redirected

The tc_from field fulfills two roles. It encodes whether a packet was
redirected by an act_mirred device and, if so, whether act_mirred was
called on ingress or egress. Split it into separate fields.

The information is needed by the special IFB loop, where packets are
taken out of the normal path by act_mirred, forwarded to IFB, then
reinjected at their original location (ingress or egress) by IFB.

The IFB device cannot use skb->tc_at_ingress, because that may have
been overwritten as the packet travels from act_mirred to ifb_xmit,
when it passes through tc_classify on the IFB egress path. Cache this
value in skb->tc_from_ingress.

That field is valid only if a packet arriving at ifb_xmit came from
act_mirred. Other packets can be crafted to reach ifb_xmit. These
must be dropped. Set tc_redirected on redirection and drop all packets
that do not have this bit set.

Both fields are set only on cloned skbs in tc actions, so original
packet sources do not have to clear the bit when reusing packets
(notably, pktgen and octeon).
Signed-off-by: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8dc07fdb
...@@ -78,9 +78,7 @@ static void ifb_ri_tasklet(unsigned long _txp) ...@@ -78,9 +78,7 @@ static void ifb_ri_tasklet(unsigned long _txp)
} }
while ((skb = __skb_dequeue(&txp->tq)) != NULL) { while ((skb = __skb_dequeue(&txp->tq)) != NULL) {
u32 from = skb->tc_from; skb->tc_redirected = 0;
skb_reset_tc(skb);
skb->tc_skip_classify = 1; skb->tc_skip_classify = 1;
u64_stats_update_begin(&txp->tsync); u64_stats_update_begin(&txp->tsync);
...@@ -101,13 +99,12 @@ static void ifb_ri_tasklet(unsigned long _txp) ...@@ -101,13 +99,12 @@ static void ifb_ri_tasklet(unsigned long _txp)
rcu_read_unlock(); rcu_read_unlock();
skb->skb_iif = txp->dev->ifindex; skb->skb_iif = txp->dev->ifindex;
if (from & AT_EGRESS) { if (!skb->tc_from_ingress) {
dev_queue_xmit(skb); dev_queue_xmit(skb);
} else if (from & AT_INGRESS) { } else {
skb_pull(skb, skb->mac_len); skb_pull(skb, skb->mac_len);
netif_receive_skb(skb); netif_receive_skb(skb);
} else }
BUG();
} }
if (__netif_tx_trylock(txq)) { if (__netif_tx_trylock(txq)) {
...@@ -246,7 +243,7 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -246,7 +243,7 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)
txp->rx_bytes += skb->len; txp->rx_bytes += skb->len;
u64_stats_update_end(&txp->rsync); u64_stats_update_end(&txp->rsync);
if (skb->tc_from == AT_STACK || !skb->skb_iif) { if (!skb->tc_redirected || !skb->skb_iif) {
dev_kfree_skb(skb); dev_kfree_skb(skb);
dev->stats.rx_dropped++; dev->stats.rx_dropped++;
return NETDEV_TX_OK; return NETDEV_TX_OK;
......
...@@ -591,6 +591,8 @@ static inline bool skb_mstamp_after(const struct skb_mstamp *t1, ...@@ -591,6 +591,8 @@ static inline bool skb_mstamp_after(const struct skb_mstamp *t1,
* @ipvs_property: skbuff is owned by ipvs * @ipvs_property: skbuff is owned by ipvs
* @tc_skip_classify: do not classify packet. set by IFB device * @tc_skip_classify: do not classify packet. set by IFB device
* @tc_at_ingress: used within tc_classify to distinguish in/egress * @tc_at_ingress: used within tc_classify to distinguish in/egress
* @tc_redirected: packet was redirected by a tc action
* @tc_from_ingress: if tc_redirected, tc_at_ingress at time of redirect
* @peeked: this packet has been seen already, so stats have been * @peeked: this packet has been seen already, so stats have been
* done for it, don't do them again * done for it, don't do them again
* @nf_trace: netfilter packet trace flag * @nf_trace: netfilter packet trace flag
...@@ -753,7 +755,8 @@ struct sk_buff { ...@@ -753,7 +755,8 @@ struct sk_buff {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
__u8 tc_skip_classify:1; __u8 tc_skip_classify:1;
__u8 tc_at_ingress:1; __u8 tc_at_ingress:1;
__u8 tc_from:2; __u8 tc_redirected:1;
__u8 tc_from_ingress:1;
#endif #endif
#ifdef CONFIG_NET_SCHED #ifdef CONFIG_NET_SCHED
......
...@@ -412,7 +412,7 @@ int skb_do_redirect(struct sk_buff *); ...@@ -412,7 +412,7 @@ int skb_do_redirect(struct sk_buff *);
static inline void skb_reset_tc(struct sk_buff *skb) static inline void skb_reset_tc(struct sk_buff *skb)
{ {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
skb->tc_from = 0; skb->tc_redirected = 0;
#endif #endif
} }
......
...@@ -4,12 +4,6 @@ ...@@ -4,12 +4,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pkt_sched.h> #include <linux/pkt_sched.h>
#ifdef __KERNEL__
#define AT_STACK 0x0
#define AT_INGRESS 0x1
#define AT_EGRESS 0x2
#endif
/* Action attributes */ /* Action attributes */
enum { enum {
TCA_ACT_UNSPEC, TCA_ACT_UNSPEC,
......
...@@ -211,8 +211,10 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, ...@@ -211,8 +211,10 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
} }
/* mirror is always swallowed */ /* mirror is always swallowed */
if (tcf_mirred_is_act_redirect(m_eaction)) if (tcf_mirred_is_act_redirect(m_eaction)) {
skb2->tc_from = skb_at_tc_ingress(skb) ? AT_INGRESS : AT_EGRESS; skb2->tc_redirected = 1;
skb2->tc_from_ingress = skb2->tc_at_ingress;
}
skb2->skb_iif = skb->dev->ifindex; skb2->skb_iif = skb->dev->ifindex;
skb2->dev = dev; skb2->dev = dev;
......
...@@ -626,7 +626,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) ...@@ -626,7 +626,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch)
* If it's at ingress let's pretend the delay is * If it's at ingress let's pretend the delay is
* from the network (tstamp will be updated). * from the network (tstamp will be updated).
*/ */
if (skb->tc_from & AT_INGRESS) if (skb->tc_redirected && skb->tc_from_ingress)
skb->tstamp = 0; skb->tstamp = 0;
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment