blob: fe278a788ba05a0a52518b9a9b93b3ccd0d83177 [file] [log] [blame]
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index c2416b1..bc13a9b 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -435,6 +435,17 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
return 0;
}
+
+int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
+{
+ u32 *ib2 = mtk_foe_entry_ib2(entry);
+
+ *ib2 &= ~MTK_FOE_IB2_DSCP;
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_DSCP, dscp);
+
+ return 0;
+}
+
static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
{
return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index e7ecbf7..df10040 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -430,6 +430,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
int bss, int wcid);
int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
+int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index 23d2048..9bc0857 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -246,6 +246,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
int wed_index = -1;
u16 addr_type = 0;
u8 l4proto = 0;
+ u8 dscp = 0;
int err = 0;
int i;
@@ -282,6 +283,15 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
return -EOPNOTSUPP;
}
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
+ struct flow_match_ip match;
+
+ flow_rule_match_ip(rule, &match);
+ dscp = match.key->tos;
+ } else {
+ return -EOPNOTSUPP;
+ }
+
switch (addr_type) {
case 0:
offload_type = MTK_PPE_PKT_TYPE_BRIDGE;
@@ -441,6 +451,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
if (data.pppoe.num == 1)
mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
+ mtk_foe_entry_set_dscp(&foe, dscp);
+
err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
&wed_index);
if (err)
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index 55359dd..1a23c03 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -36,6 +36,7 @@ struct nf_flow_key {
};
struct flow_dissector_key_tcp tcp;
struct flow_dissector_key_ports tp;
+ struct flow_dissector_key_ip ip;
} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
struct nf_flow_match {
@@ -145,6 +146,7 @@ struct flow_offload_tuple {
u8 h_dest[ETH_ALEN];
} out;
};
+ u8 tos;
};
struct flow_offload_tuple_rhash {
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index 61cc518..c1a5f64 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -104,6 +104,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp);
NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp);
+ NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IP, ip);
if (other_dst && other_dst->lwtstate) {
tun_info = lwt_tun_info(other_dst->lwtstate);
@@ -183,10 +184,14 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
key->tp.dst = tuple->dst_port;
mask->tp.dst = 0xffff;
+ key->ip.tos = tuple->tos;
+ mask->ip.tos = 0xff;
+
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) |
BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_PORTS);
+ BIT(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT(FLOW_DISSECTOR_KEY_IP);
return 0;
}
diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
index 2d5c3cc..b231dd7 100644
--- a/net/netfilter/xt_FLOWOFFLOAD.c
+++ b/net/netfilter/xt_FLOWOFFLOAD.c
@@ -49,6 +49,35 @@ static DEFINE_SPINLOCK(hooks_lock);
struct xt_flowoffload_table flowtable[2];
+static int
+xt_flowoffload_dscp_init(struct sk_buff *skb, struct flow_offload *flow,
+ enum ip_conntrack_dir dir)
+{
+ const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ u32 offset = 0;
+ u8 tos = 0;
+
+ switch (flow_tuple->l3proto) {
+ case NFPROTO_IPV4:
+ iph = (struct iphdr *)(skb_network_header(skb) + offset);
+ tos = iph->tos;
+ break;
+ case NFPROTO_IPV6:
+ ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
+ tos = ipv6_get_dsfield(ip6h);
+ break;
+ default:
+ return -1;
+ };
+
+ flow->tuplehash[dir].tuple.tos = tos;
+ flow->tuplehash[!dir].tuple.tos = tos;
+
+ return 0;
+}
+
static unsigned int
xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
@@ -599,6 +628,9 @@ flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
if (flow_offload_route_init(flow, &route) < 0)
goto err_flow_add;
+ if (xt_flowoffload_dscp_init(skb, flow, dir) < 0)
+ goto err_flow_add;
+
if (tcph) {
ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;