net-tc: convert tc_from to tc_from_ingress and tc_redirected
authorWillem de Bruijn <willemb@google.com>
Sat, 7 Jan 2017 22:06:38 +0000 (17:06 -0500)
committerDavid S. Miller <davem@davemloft.net>
Mon, 9 Jan 2017 01:58:52 +0000 (20:58 -0500)
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: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ifb.c
include/linux/skbuff.h
include/net/sch_generic.h
include/uapi/linux/pkt_cls.h
net/sched/act_mirred.c
net/sched/sch_netem.c

index b73b6b6c066b148bdb649b95385cbeace14a392a..312fce7302d3252903282599223063e7d97bb863 100644 (file)
@@ -78,9 +78,7 @@ static void ifb_ri_tasklet(unsigned long _txp)
        }
 
        while ((skb = __skb_dequeue(&txp->tq)) != NULL) {
-               u32 from = skb->tc_from;
-
-               skb_reset_tc(skb);
+               skb->tc_redirected = 0;
                skb->tc_skip_classify = 1;
 
                u64_stats_update_begin(&txp->tsync);
@@ -101,13 +99,12 @@ static void ifb_ri_tasklet(unsigned long _txp)
                rcu_read_unlock();
                skb->skb_iif = txp->dev->ifindex;
 
-               if (from & AT_EGRESS) {
+               if (!skb->tc_from_ingress) {
                        dev_queue_xmit(skb);
-               } else if (from & AT_INGRESS) {
+               } else {
                        skb_pull(skb, skb->mac_len);
                        netif_receive_skb(skb);
-               } else
-                       BUG();
+               }
        }
 
        if (__netif_tx_trylock(txq)) {
@@ -246,7 +243,7 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)
        txp->rx_bytes += skb->len;
        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->stats.rx_dropped++;
                return NETDEV_TX_OK;
index fab3f87e9bd139a4ef566c03dcca87a23668c098..3149a88de548368ce3c8d88947034ba7d5615683 100644 (file)
@@ -591,6 +591,8 @@ static inline bool skb_mstamp_after(const struct skb_mstamp *t1,
  *     @ipvs_property: skbuff is owned by ipvs
  *     @tc_skip_classify: do not classify packet. set by IFB device
  *     @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
  *             done for it, don't do them again
  *     @nf_trace: netfilter packet trace flag
@@ -753,7 +755,8 @@ struct sk_buff {
 #ifdef CONFIG_NET_CLS_ACT
        __u8                    tc_skip_classify:1;
        __u8                    tc_at_ingress:1;
-       __u8                    tc_from:2;
+       __u8                    tc_redirected:1;
+       __u8                    tc_from_ingress:1;
 #endif
 
 #ifdef CONFIG_NET_SCHED
index 4bd6d53872099120af02067153b69418b2385cb9..e2f426f6d62f760ff7c4f6deb69947daa39cbe14 100644 (file)
@@ -412,7 +412,7 @@ int skb_do_redirect(struct sk_buff *);
 static inline void skb_reset_tc(struct sk_buff *skb)
 {
 #ifdef CONFIG_NET_CLS_ACT
-       skb->tc_from = 0;
+       skb->tc_redirected = 0;
 #endif
 }
 
index cee753a7a40ce925a5a94157a6088f7a6dacf1ae..a081efbd61a27426a9e8bdd12e7c94c165a8d194 100644 (file)
@@ -4,12 +4,6 @@
 #include <linux/types.h>
 #include <linux/pkt_sched.h>
 
-#ifdef __KERNEL__
-#define AT_STACK       0x0
-#define AT_INGRESS     0x1
-#define AT_EGRESS      0x2
-#endif
-
 /* Action attributes */
 enum {
        TCA_ACT_UNSPEC,
index e832c62fd705850711d39edf4a35af07e4e80c9b..84682f02b611f8f3f339463e2a19738c5a9d2897 100644 (file)
@@ -211,8 +211,10 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
        }
 
        /* mirror is always swallowed */
-       if (tcf_mirred_is_act_redirect(m_eaction))
-               skb2->tc_from = skb_at_tc_ingress(skb) ? AT_INGRESS : AT_EGRESS;
+       if (tcf_mirred_is_act_redirect(m_eaction)) {
+               skb2->tc_redirected = 1;
+               skb2->tc_from_ingress = skb2->tc_at_ingress;
+       }
 
        skb2->skb_iif = skb->dev->ifindex;
        skb2->dev = dev;
index bb5c638b685262a827924deed8b4b113d9ed83eb..c8bb62a1e7449344a0fd81241fe0102ea2f9c0f9 100644 (file)
@@ -626,7 +626,7 @@ deliver:
                         * If it's at ingress let's pretend the delay is
                         * from the network (tstamp will be updated).
                         */
-                       if (skb->tc_from & AT_INGRESS)
+                       if (skb->tc_redirected && skb->tc_from_ingress)
                                skb->tstamp = 0;
 #endif