|
@@ -115,12 +115,6 @@ __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
|
|
|
}
|
|
|
EXPORT_SYMBOL(__skb_flow_get_ports);
|
|
|
|
|
|
-enum flow_dissect_ret {
|
|
|
- FLOW_DISSECT_RET_OUT_GOOD,
|
|
|
- FLOW_DISSECT_RET_OUT_BAD,
|
|
|
- FLOW_DISSECT_RET_OUT_PROTO_AGAIN,
|
|
|
-};
|
|
|
-
|
|
|
static enum flow_dissect_ret
|
|
|
__skb_flow_dissect_mpls(const struct sk_buff *skb,
|
|
|
struct flow_dissector *flow_dissector,
|
|
@@ -341,7 +335,7 @@ __skb_flow_dissect_gre(const struct sk_buff *skb,
|
|
|
if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
|
|
|
return FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
|
|
|
- return FLOW_DISSECT_RET_OUT_PROTO_AGAIN;
|
|
|
+ return FLOW_DISSECT_RET_PROTO_AGAIN;
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -431,6 +425,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
|
|
|
struct flow_dissector_key_icmp *key_icmp;
|
|
|
struct flow_dissector_key_tags *key_tags;
|
|
|
struct flow_dissector_key_vlan *key_vlan;
|
|
|
+ enum flow_dissect_ret fdret;
|
|
|
bool skip_vlan = false;
|
|
|
u8 ip_proto = 0;
|
|
|
bool ret;
|
|
@@ -482,14 +477,19 @@ bool __skb_flow_dissect(const struct sk_buff *skb,
|
|
|
}
|
|
|
|
|
|
proto_again:
|
|
|
+ fdret = FLOW_DISSECT_RET_CONTINUE;
|
|
|
+
|
|
|
switch (proto) {
|
|
|
case htons(ETH_P_IP): {
|
|
|
const struct iphdr *iph;
|
|
|
struct iphdr _iph;
|
|
|
-ip:
|
|
|
+
|
|
|
iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
|
|
|
- if (!iph || iph->ihl < 5)
|
|
|
- goto out_bad;
|
|
|
+ if (!iph || iph->ihl < 5) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
nhoff += iph->ihl * 4;
|
|
|
|
|
|
ip_proto = iph->protocol;
|
|
@@ -509,19 +509,25 @@ ip:
|
|
|
key_control->flags |= FLOW_DIS_IS_FRAGMENT;
|
|
|
|
|
|
if (iph->frag_off & htons(IP_OFFSET)) {
|
|
|
- goto out_good;
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
} else {
|
|
|
key_control->flags |= FLOW_DIS_FIRST_FRAG;
|
|
|
- if (!(flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG))
|
|
|
- goto out_good;
|
|
|
+ if (!(flags &
|
|
|
+ FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
__skb_flow_dissect_ipv4(skb, flow_dissector,
|
|
|
target_container, data, iph);
|
|
|
|
|
|
- if (flags & FLOW_DISSECTOR_F_STOP_AT_L3)
|
|
|
- goto out_good;
|
|
|
+ if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
break;
|
|
|
}
|
|
@@ -529,10 +535,11 @@ ip:
|
|
|
const struct ipv6hdr *iph;
|
|
|
struct ipv6hdr _iph;
|
|
|
|
|
|
-ipv6:
|
|
|
iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
|
|
|
- if (!iph)
|
|
|
- goto out_bad;
|
|
|
+ if (!iph) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
ip_proto = iph->nexthdr;
|
|
|
nhoff += sizeof(struct ipv6hdr);
|
|
@@ -561,15 +568,17 @@ ipv6:
|
|
|
target_container);
|
|
|
key_tags->flow_label = ntohl(flow_label);
|
|
|
}
|
|
|
- if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)
|
|
|
- goto out_good;
|
|
|
+ if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
__skb_flow_dissect_ipv6(skb, flow_dissector,
|
|
|
target_container, data, iph);
|
|
|
|
|
|
if (flags & FLOW_DISSECTOR_F_STOP_AT_L3)
|
|
|
- goto out_good;
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
|
|
|
break;
|
|
|
}
|
|
@@ -585,12 +594,17 @@ ipv6:
|
|
|
if (!vlan_tag_present || eth_type_vlan(skb->protocol)) {
|
|
|
vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan),
|
|
|
data, hlen, &_vlan);
|
|
|
- if (!vlan)
|
|
|
- goto out_bad;
|
|
|
+ if (!vlan) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
proto = vlan->h_vlan_encapsulated_proto;
|
|
|
nhoff += sizeof(*vlan);
|
|
|
- if (skip_vlan)
|
|
|
- goto proto_again;
|
|
|
+ if (skip_vlan) {
|
|
|
+ fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
skip_vlan = true;
|
|
@@ -613,7 +627,8 @@ ipv6:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- goto proto_again;
|
|
|
+ fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
|
|
|
+ break;
|
|
|
}
|
|
|
case htons(ETH_P_PPP_SES): {
|
|
|
struct {
|
|
@@ -621,18 +636,27 @@ ipv6:
|
|
|
__be16 proto;
|
|
|
} *hdr, _hdr;
|
|
|
hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
|
|
|
- if (!hdr)
|
|
|
- goto out_bad;
|
|
|
+ if (!hdr) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
proto = hdr->proto;
|
|
|
nhoff += PPPOE_SES_HLEN;
|
|
|
switch (proto) {
|
|
|
case htons(PPP_IP):
|
|
|
- goto ip;
|
|
|
+ proto = htons(ETH_P_IP);
|
|
|
+ fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
|
|
|
+ break;
|
|
|
case htons(PPP_IPV6):
|
|
|
- goto ipv6;
|
|
|
+ proto = htons(ETH_P_IPV6);
|
|
|
+ fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
|
|
|
+ break;
|
|
|
default:
|
|
|
- goto out_bad;
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
}
|
|
|
+ break;
|
|
|
}
|
|
|
case htons(ETH_P_TIPC): {
|
|
|
struct {
|
|
@@ -640,8 +664,10 @@ ipv6:
|
|
|
__be32 srcnode;
|
|
|
} *hdr, _hdr;
|
|
|
hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
|
|
|
- if (!hdr)
|
|
|
- goto out_bad;
|
|
|
+ if (!hdr) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
if (dissector_uses_key(flow_dissector,
|
|
|
FLOW_DISSECTOR_KEY_TIPC_ADDRS)) {
|
|
@@ -651,56 +677,62 @@ ipv6:
|
|
|
key_addrs->tipcaddrs.srcnode = hdr->srcnode;
|
|
|
key_control->addr_type = FLOW_DISSECTOR_KEY_TIPC_ADDRS;
|
|
|
}
|
|
|
- goto out_good;
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
case htons(ETH_P_MPLS_UC):
|
|
|
case htons(ETH_P_MPLS_MC):
|
|
|
-mpls:
|
|
|
- switch (__skb_flow_dissect_mpls(skb, flow_dissector,
|
|
|
+ fdret = __skb_flow_dissect_mpls(skb, flow_dissector,
|
|
|
target_container, data,
|
|
|
- nhoff, hlen)) {
|
|
|
- case FLOW_DISSECT_RET_OUT_GOOD:
|
|
|
- goto out_good;
|
|
|
- case FLOW_DISSECT_RET_OUT_BAD:
|
|
|
- default:
|
|
|
- goto out_bad;
|
|
|
- }
|
|
|
+ nhoff, hlen);
|
|
|
+ break;
|
|
|
case htons(ETH_P_FCOE):
|
|
|
- if ((hlen - nhoff) < FCOE_HEADER_LEN)
|
|
|
- goto out_bad;
|
|
|
+ if ((hlen - nhoff) < FCOE_HEADER_LEN) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
nhoff += FCOE_HEADER_LEN;
|
|
|
- goto out_good;
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
|
|
|
case htons(ETH_P_ARP):
|
|
|
case htons(ETH_P_RARP):
|
|
|
- switch (__skb_flow_dissect_arp(skb, flow_dissector,
|
|
|
+ fdret = __skb_flow_dissect_arp(skb, flow_dissector,
|
|
|
target_container, data,
|
|
|
- nhoff, hlen)) {
|
|
|
- case FLOW_DISSECT_RET_OUT_GOOD:
|
|
|
- goto out_good;
|
|
|
- case FLOW_DISSECT_RET_OUT_BAD:
|
|
|
- default:
|
|
|
- goto out_bad;
|
|
|
- }
|
|
|
+ nhoff, hlen);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Process result of proto processing */
|
|
|
+ switch (fdret) {
|
|
|
+ case FLOW_DISSECT_RET_OUT_GOOD:
|
|
|
+ goto out_good;
|
|
|
+ case FLOW_DISSECT_RET_PROTO_AGAIN:
|
|
|
+ goto proto_again;
|
|
|
+ case FLOW_DISSECT_RET_CONTINUE:
|
|
|
+ case FLOW_DISSECT_RET_IPPROTO_AGAIN:
|
|
|
+ break;
|
|
|
+ case FLOW_DISSECT_RET_OUT_BAD:
|
|
|
default:
|
|
|
goto out_bad;
|
|
|
}
|
|
|
|
|
|
ip_proto_again:
|
|
|
+ fdret = FLOW_DISSECT_RET_CONTINUE;
|
|
|
+
|
|
|
switch (ip_proto) {
|
|
|
case IPPROTO_GRE:
|
|
|
- switch (__skb_flow_dissect_gre(skb, key_control, flow_dissector,
|
|
|
+ fdret = __skb_flow_dissect_gre(skb, key_control, flow_dissector,
|
|
|
target_container, data,
|
|
|
- &proto, &nhoff, &hlen, flags)) {
|
|
|
- case FLOW_DISSECT_RET_OUT_GOOD:
|
|
|
- goto out_good;
|
|
|
- case FLOW_DISSECT_RET_OUT_BAD:
|
|
|
- goto out_bad;
|
|
|
- case FLOW_DISSECT_RET_OUT_PROTO_AGAIN:
|
|
|
- goto proto_again;
|
|
|
- }
|
|
|
+ &proto, &nhoff, &hlen, flags);
|
|
|
+ break;
|
|
|
+
|
|
|
case NEXTHDR_HOP:
|
|
|
case NEXTHDR_ROUTING:
|
|
|
case NEXTHDR_DEST: {
|
|
@@ -711,13 +743,16 @@ ip_proto_again:
|
|
|
|
|
|
opthdr = __skb_header_pointer(skb, nhoff, sizeof(_opthdr),
|
|
|
data, hlen, &_opthdr);
|
|
|
- if (!opthdr)
|
|
|
- goto out_bad;
|
|
|
+ if (!opthdr) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
ip_proto = opthdr[0];
|
|
|
nhoff += (opthdr[1] + 1) << 3;
|
|
|
|
|
|
- goto ip_proto_again;
|
|
|
+ fdret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
|
|
|
+ break;
|
|
|
}
|
|
|
case NEXTHDR_FRAGMENT: {
|
|
|
struct frag_hdr _fh, *fh;
|
|
@@ -728,8 +763,10 @@ ip_proto_again:
|
|
|
fh = __skb_header_pointer(skb, nhoff, sizeof(_fh),
|
|
|
data, hlen, &_fh);
|
|
|
|
|
|
- if (!fh)
|
|
|
- goto out_bad;
|
|
|
+ if (!fh) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_BAD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
key_control->flags |= FLOW_DIS_IS_FRAGMENT;
|
|
|
|
|
@@ -738,34 +775,50 @@ ip_proto_again:
|
|
|
|
|
|
if (!(fh->frag_off & htons(IP6_OFFSET))) {
|
|
|
key_control->flags |= FLOW_DIS_FIRST_FRAG;
|
|
|
- if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)
|
|
|
- goto ip_proto_again;
|
|
|
+ if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) {
|
|
|
+ fdret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- goto out_good;
|
|
|
+
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
}
|
|
|
case IPPROTO_IPIP:
|
|
|
proto = htons(ETH_P_IP);
|
|
|
|
|
|
key_control->flags |= FLOW_DIS_ENCAPSULATION;
|
|
|
- if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
|
|
|
- goto out_good;
|
|
|
+ if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
|
|
|
+ break;
|
|
|
|
|
|
- goto ip;
|
|
|
case IPPROTO_IPV6:
|
|
|
proto = htons(ETH_P_IPV6);
|
|
|
|
|
|
key_control->flags |= FLOW_DIS_ENCAPSULATION;
|
|
|
- if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
|
|
|
- goto out_good;
|
|
|
+ if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) {
|
|
|
+ fdret = FLOW_DISSECT_RET_OUT_GOOD;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
|
|
|
+ break;
|
|
|
+
|
|
|
|
|
|
- goto ipv6;
|
|
|
case IPPROTO_MPLS:
|
|
|
proto = htons(ETH_P_MPLS_UC);
|
|
|
- goto mpls;
|
|
|
+ fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
|
|
|
+ break;
|
|
|
+
|
|
|
case IPPROTO_TCP:
|
|
|
__skb_flow_dissect_tcp(skb, flow_dissector, target_container,
|
|
|
data, nhoff, hlen);
|
|
|
break;
|
|
|
+
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
@@ -787,6 +840,20 @@ ip_proto_again:
|
|
|
key_icmp->icmp = skb_flow_get_be16(skb, nhoff, data, hlen);
|
|
|
}
|
|
|
|
|
|
+ /* Process result of IP proto processing */
|
|
|
+ switch (fdret) {
|
|
|
+ case FLOW_DISSECT_RET_PROTO_AGAIN:
|
|
|
+ goto proto_again;
|
|
|
+ case FLOW_DISSECT_RET_IPPROTO_AGAIN:
|
|
|
+ goto ip_proto_again;
|
|
|
+ case FLOW_DISSECT_RET_OUT_GOOD:
|
|
|
+ case FLOW_DISSECT_RET_CONTINUE:
|
|
|
+ break;
|
|
|
+ case FLOW_DISSECT_RET_OUT_BAD:
|
|
|
+ default:
|
|
|
+ goto out_bad;
|
|
|
+ }
|
|
|
+
|
|
|
out_good:
|
|
|
ret = true;
|
|
|
|