diff options
author | Sachin Saxena <sachin.saxena@freescale.com> | 2013-04-15 09:53:06 (GMT) |
---|---|---|
committer | Fleming Andrew-AFLEMING <AFLEMING@freescale.com> | 2013-04-16 22:40:26 (GMT) |
commit | 2559f18bc5045d73e120556d4127496407125a25 (patch) | |
tree | 41853e4b95e1f9f413c43919373a0f65d9d91fe6 | |
parent | 107eeafdd3d8dd59d4c493460902ce5d79269068 (diff) | |
download | linux-fsl-qoriq-2559f18bc5045d73e120556d4127496407125a25.tar.xz |
ASF_QOS: Adding Hooks to offload Marking Rules.
- Support added to offload both Rules via iptables &ip6tables tool
- Only MANGLE table supported with POSTROUTING Hook.
Signed-off-by: Sachin Saxena <sachin.saxena@freescale.com>
CQ ID : ENGR00253307
Change-Id: I4df4245091ef0e195e058dce4fb611b04746061c
Reviewed-on: http://git.am.freescale.net:8181/1346
Reviewed-by: Gupta Rajan-B15745 <rajan.gupta@freescale.com>
Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
-rw-r--r-- | include/linux/netfilter.h | 29 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 74 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 76 |
3 files changed, 178 insertions, 1 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index ee14284..0bcef390 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -342,4 +342,33 @@ extern struct nfq_ct_nat_hook __rcu *nfq_ct_nat_hook; static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} #endif +#ifdef CONFIG_ASF_INGRESS_MARKER +#define MAX_MARKER_RULES 20 + +typedef struct { + uint32_t src_ip[4]; + uint32_t dst_ip[4]; + uint16_t src_port; + uint16_t dst_port; + uint8_t proto; + uint8_t uciDscp; +} markerRule_t; + +typedef struct { + markerRule_t *rule; + uint32_t num_rules; +} marker_db_t; + +typedef int marker_add_hook(marker_db_t *arg); +typedef void marker_flush_hook(void); + +extern marker_add_hook *marker_add_fn; +extern marker_flush_hook *marker_flush_fn; + +void marker_v4_hook_fn_register(marker_add_hook *add, + marker_flush_hook *flush); +void marker_v6_hook_fn_register(marker_add_hook *add, + marker_flush_hook *flush); +#endif + #endif /*__LINUX_NETFILTER_H*/ diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 56a1b72..537b249 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -62,6 +62,19 @@ MODULE_DESCRIPTION("IPv4 packet filter"); #define inline #endif +#ifdef CONFIG_ASF_INGRESS_MARKER +marker_add_hook *marker_add_fn; +marker_flush_hook *marker_flush_fn; + +void marker_v4_hook_fn_register(marker_add_hook *add, + marker_flush_hook *flush) +{ + marker_add_fn = add; + marker_flush_fn = flush; +} +EXPORT_SYMBOL(marker_v4_hook_fn_register); +#endif + void *ipt_alloc_initial_table(const struct xt_table *info) { return xt_alloc_initial_table(ipt, IPT); @@ -818,6 +831,7 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, ++newinfo->stacksize; } + if (i != repl->num_entries) { duprintf("translate_table: %u not %u entries\n", i, repl->num_entries); @@ -868,6 +882,65 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, memcpy(newinfo->entries[i], entry0, newinfo->size); } +#ifdef CONFIG_ASF_INGRESS_MARKER + /* Rules has been verified now safe to offload to ASF */ + if (marker_add_fn && (0 == strcmp(repl->name, "mangle"))) { + struct xt_entry_match *m; + struct xt_entry_target *t; + markerRule_t rules[MAX_MARKER_RULES] = {}; + uint16_t *sport, *dport; + uint32_t num = 0; + + /* Whether It is FLUSH request ? */ + /* Note: num_entries are always equals to num_counters +1, when adding Rules + while num_entries comes as '6' as default value when FLUSH is required */ + if ((repl->num_entries == 6) && (repl->num_entries < repl->num_counters)) { + if (marker_flush_fn) + marker_flush_fn(); + return ret; + } + xt_entry_foreach(iter, entry0, newinfo->size) + { + /* Only POSTROUTING CHAINS */ + if (iter->comefrom != (0x1 << NF_INET_POST_ROUTING)) + continue; + if ((iter->ip.proto != 17/*UDP */) && + (iter->ip.proto != 6/*TCP */)) + continue; + + if (num == MAX_MARKER_RULES) { + printk(KERN_INFO "Maximum %d Rule permitted\n", + MAX_MARKER_RULES); + break; + } + m = (void *)iter + sizeof(struct ipt_entry); + t = (void *)iter + iter->target_offset; + if (0 != strcmp(t->u.kernel.target->name, "DSCP")) + continue; + + rules[num].src_ip[0] = iter->ip.src.s_addr; + rules[num].dst_ip[0] = iter->ip.dst.s_addr; + rules[num].proto = iter->ip.proto; + /* We are passing Port Mask instead of Value , since mask = value. + But when Port are not configured, we get 0xFFFF to indicate that + ANY port value is accepted. */ + sport = (uint16_t *)&m->data[2]; + dport = (uint16_t *)&m->data[6]; + rules[num].src_port = *sport; + rules[num].dst_port = *dport; + rules[num].uciDscp = (t->data[0] << 2); + + num++; + } + if (num > 0) { + marker_db_t arg; + + arg.rule = &rules[0]; + arg.num_rules = num; + marker_add_fn(&arg); + } + } +#endif return ret; } @@ -976,7 +1049,6 @@ copy_entries_to_user(unsigned int total_size, goto free_counters; } } - t = ipt_get_target_c(e); if (copy_to_user(userptr + off + e->target_offset + offsetof(struct xt_entry_target, diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 84d9931..f90992e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -62,6 +62,18 @@ MODULE_DESCRIPTION("IPv6 packet filter"); #define static #define inline #endif +#ifdef CONFIG_ASF_INGRESS_MARKER +marker_add_hook *marker_v6_add_fn; +marker_flush_hook *marker_v6_flush_fn; + +void marker_v6_hook_fn_register(marker_add_hook *add, + marker_flush_hook *flush) +{ + marker_v6_add_fn = add; + marker_v6_flush_fn = flush; +} +EXPORT_SYMBOL(marker_v6_hook_fn_register); +#endif void *ip6t_alloc_initial_table(const struct xt_table *info) { @@ -876,6 +888,70 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, memcpy(newinfo->entries[i], entry0, newinfo->size); } +#ifdef CONFIG_ASF_INGRESS_MARKER + /* Rules has been verified now safe to offload to ASF */ + if (marker_v6_add_fn && (0 == strcmp(repl->name, "mangle"))) { + struct xt_entry_match *m; + struct xt_entry_target *t; + markerRule_t rules[MAX_MARKER_RULES] = {}; + uint16_t *sport, *dport; + uint32_t num = 0; + + /* Whether It is FLUSH request ? */ + /* Note: num_entries are always equals to num_counters +1, when adding Rules + while num_entries comes as '6' as default value when FLUSH is required */ + if ((repl->num_entries == 6) && (repl->num_entries < repl->num_counters)) { + if (marker_v6_flush_fn) + marker_v6_flush_fn(); + return ret; + } + xt_entry_foreach(iter, entry0, newinfo->size) + { + /* Only POSTROUTING CHAINS */ + if (iter->comefrom != (0x1 << NF_INET_POST_ROUTING)) + continue; + if ((iter->ipv6.proto != 17/*UDP */) && (iter->ipv6.proto != 6/*TCP */)) + continue; + + if (num == MAX_MARKER_RULES) { + printk(KERN_INFO "Maximum %d Rule permitted\n", + MAX_MARKER_RULES); + break; + } + m = (void *)iter + sizeof(struct ip6t_entry); + t = (void *)iter + iter->target_offset; + if (0 != strcmp(t->u.kernel.target->name, "DSCP")) + continue; + + rules[num].src_ip[0] = iter->ipv6.src.in6_u.u6_addr32[0]; + rules[num].src_ip[1] = iter->ipv6.src.in6_u.u6_addr32[1]; + rules[num].src_ip[2] = iter->ipv6.src.in6_u.u6_addr32[2]; + rules[num].src_ip[3] = iter->ipv6.src.in6_u.u6_addr32[3]; + rules[num].dst_ip[0] = iter->ipv6.dst.in6_u.u6_addr32[0]; + rules[num].dst_ip[1] = iter->ipv6.dst.in6_u.u6_addr32[1]; + rules[num].dst_ip[2] = iter->ipv6.dst.in6_u.u6_addr32[2]; + rules[num].dst_ip[3] = iter->ipv6.dst.in6_u.u6_addr32[3]; + rules[num].proto = iter->ipv6.proto; + /* We are passing Port Mask instead of Value , since mask = value. + But when Port are not configured, we get 0xFFFF to indicate that + ANY port value is accepted. */ + sport = (uint16_t *)&m->data[2]; + dport = (uint16_t *)&m->data[6]; + rules[num].src_port = *sport; + rules[num].dst_port = *dport; + rules[num].uciDscp = (t->data[0] << 2); + + num++; + } + if (num > 0) { + marker_db_t arg; + + arg.rule = &rules[0]; + arg.num_rules = num; + marker_v6_add_fn(&arg); + } + } +#endif return ret; } |