Loading net/sched/sch_choke.c +31 −89 Original line number Diff line number Diff line Loading @@ -19,10 +19,7 @@ #include <net/pkt_sched.h> #include <net/inet_ecn.h> #include <net/red.h> #include <linux/ip.h> #include <net/ip.h> #include <linux/ipv6.h> #include <net/ipv6.h> #include <net/flow_keys.h> /* CHOKe stateless AQM for fair bandwidth allocation Loading Loading @@ -142,92 +139,10 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx) --sch->q.qlen; } /* * Compare flow of two packets * Returns true only if source and destination address and port match. * false for special cases */ static bool choke_match_flow(struct sk_buff *skb1, struct sk_buff *skb2) { int off1, off2, poff; const u32 *ports1, *ports2; u32 _ports1, _ports2; u8 ip_proto; __u32 hash1; if (skb1->protocol != skb2->protocol) return false; /* Use rxhash value as quick check */ hash1 = skb_get_rxhash(skb1); if (!hash1 || hash1 != skb_get_rxhash(skb2)) return false; /* Probably match, but be sure to avoid hash collisions */ off1 = skb_network_offset(skb1); off2 = skb_network_offset(skb2); switch (skb1->protocol) { case __constant_htons(ETH_P_IP): { const struct iphdr *ip1, *ip2; struct iphdr _ip1, _ip2; ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1); ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2); if (!ip1 || !ip2) return false; ip_proto = ip1->protocol; if (ip_proto != ip2->protocol || ip1->saddr != ip2->saddr || ip1->daddr != ip2->daddr) return false; if (ip_is_fragment(ip1) | ip_is_fragment(ip2)) ip_proto = 0; off1 += ip1->ihl * 4; off2 += ip2->ihl * 4; break; } case __constant_htons(ETH_P_IPV6): { const struct ipv6hdr *ip1, *ip2; struct ipv6hdr _ip1, _ip2; ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1); ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2); if (!ip1 || !ip2) return false; ip_proto = ip1->nexthdr; if (ip_proto != ip2->nexthdr || ipv6_addr_cmp(&ip1->saddr, &ip2->saddr) || ipv6_addr_cmp(&ip1->daddr, &ip2->daddr)) return false; off1 += 40; off2 += 40; } default: /* Maybe compare MAC header here? */ return false; } poff = proto_ports_offset(ip_proto); if (poff < 0) return true; off1 += poff; off2 += poff; ports1 = skb_header_pointer(skb1, off1, sizeof(_ports1), &_ports1); ports2 = skb_header_pointer(skb2, off2, sizeof(_ports2), &_ports2); if (!ports1 || !ports2) return false; return *ports1 == *ports2; } struct choke_skb_cb { u16 classid; u8 keys_valid; struct flow_keys keys; }; static inline struct choke_skb_cb *choke_skb_cb(const struct sk_buff *skb) Loading @@ -247,6 +162,32 @@ static u16 choke_get_classid(const struct sk_buff *skb) return choke_skb_cb(skb)->classid; } /* * Compare flow of two packets * Returns true only if source and destination address and port match. * false for special cases */ static bool choke_match_flow(struct sk_buff *skb1, struct sk_buff *skb2) { if (skb1->protocol != skb2->protocol) return false; if (!choke_skb_cb(skb1)->keys_valid) { choke_skb_cb(skb1)->keys_valid = 1; skb_flow_dissect(skb1, &choke_skb_cb(skb1)->keys); } if (!choke_skb_cb(skb2)->keys_valid) { choke_skb_cb(skb2)->keys_valid = 1; skb_flow_dissect(skb2, &choke_skb_cb(skb2)->keys); } return !memcmp(&choke_skb_cb(skb1)->keys, &choke_skb_cb(skb2)->keys, sizeof(struct flow_keys)); } /* * Classify flow using either: * 1. pre-existing classification result in skb Loading Loading @@ -333,6 +274,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch) goto other_drop; /* Packet was eaten by filter */ } choke_skb_cb(skb)->keys_valid = 0; /* Compute average queue usage (see RED) */ p->qavg = red_calc_qavg(p, sch->q.qlen); if (red_is_idling(p)) Loading Loading
net/sched/sch_choke.c +31 −89 Original line number Diff line number Diff line Loading @@ -19,10 +19,7 @@ #include <net/pkt_sched.h> #include <net/inet_ecn.h> #include <net/red.h> #include <linux/ip.h> #include <net/ip.h> #include <linux/ipv6.h> #include <net/ipv6.h> #include <net/flow_keys.h> /* CHOKe stateless AQM for fair bandwidth allocation Loading Loading @@ -142,92 +139,10 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx) --sch->q.qlen; } /* * Compare flow of two packets * Returns true only if source and destination address and port match. * false for special cases */ static bool choke_match_flow(struct sk_buff *skb1, struct sk_buff *skb2) { int off1, off2, poff; const u32 *ports1, *ports2; u32 _ports1, _ports2; u8 ip_proto; __u32 hash1; if (skb1->protocol != skb2->protocol) return false; /* Use rxhash value as quick check */ hash1 = skb_get_rxhash(skb1); if (!hash1 || hash1 != skb_get_rxhash(skb2)) return false; /* Probably match, but be sure to avoid hash collisions */ off1 = skb_network_offset(skb1); off2 = skb_network_offset(skb2); switch (skb1->protocol) { case __constant_htons(ETH_P_IP): { const struct iphdr *ip1, *ip2; struct iphdr _ip1, _ip2; ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1); ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2); if (!ip1 || !ip2) return false; ip_proto = ip1->protocol; if (ip_proto != ip2->protocol || ip1->saddr != ip2->saddr || ip1->daddr != ip2->daddr) return false; if (ip_is_fragment(ip1) | ip_is_fragment(ip2)) ip_proto = 0; off1 += ip1->ihl * 4; off2 += ip2->ihl * 4; break; } case __constant_htons(ETH_P_IPV6): { const struct ipv6hdr *ip1, *ip2; struct ipv6hdr _ip1, _ip2; ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1); ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2); if (!ip1 || !ip2) return false; ip_proto = ip1->nexthdr; if (ip_proto != ip2->nexthdr || ipv6_addr_cmp(&ip1->saddr, &ip2->saddr) || ipv6_addr_cmp(&ip1->daddr, &ip2->daddr)) return false; off1 += 40; off2 += 40; } default: /* Maybe compare MAC header here? */ return false; } poff = proto_ports_offset(ip_proto); if (poff < 0) return true; off1 += poff; off2 += poff; ports1 = skb_header_pointer(skb1, off1, sizeof(_ports1), &_ports1); ports2 = skb_header_pointer(skb2, off2, sizeof(_ports2), &_ports2); if (!ports1 || !ports2) return false; return *ports1 == *ports2; } struct choke_skb_cb { u16 classid; u8 keys_valid; struct flow_keys keys; }; static inline struct choke_skb_cb *choke_skb_cb(const struct sk_buff *skb) Loading @@ -247,6 +162,32 @@ static u16 choke_get_classid(const struct sk_buff *skb) return choke_skb_cb(skb)->classid; } /* * Compare flow of two packets * Returns true only if source and destination address and port match. * false for special cases */ static bool choke_match_flow(struct sk_buff *skb1, struct sk_buff *skb2) { if (skb1->protocol != skb2->protocol) return false; if (!choke_skb_cb(skb1)->keys_valid) { choke_skb_cb(skb1)->keys_valid = 1; skb_flow_dissect(skb1, &choke_skb_cb(skb1)->keys); } if (!choke_skb_cb(skb2)->keys_valid) { choke_skb_cb(skb2)->keys_valid = 1; skb_flow_dissect(skb2, &choke_skb_cb(skb2)->keys); } return !memcmp(&choke_skb_cb(skb1)->keys, &choke_skb_cb(skb2)->keys, sizeof(struct flow_keys)); } /* * Classify flow using either: * 1. pre-existing classification result in skb Loading Loading @@ -333,6 +274,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch) goto other_drop; /* Packet was eaten by filter */ } choke_skb_cb(skb)->keys_valid = 0; /* Compute average queue usage (see RED) */ p->qavg = red_calc_qavg(p, sch->q.qlen); if (red_is_idling(p)) Loading