net: openvswitch: IPv6: Add IPv6 extension header support
This change adds a new OpenFlow field OFPXMT_OFB_IPV6_EXTHDR and packets can be filtered using ipv6_ext flag. Signed-off-by: Toms Atteka <cpp.code.lv@gmail.com> Acked-by: Pravin B Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
a46e3d5eb7
commit
28a3f06017
@@ -241,6 +241,144 @@ static bool icmphdr_ok(struct sk_buff *skb)
|
||||
sizeof(struct icmphdr));
|
||||
}
|
||||
|
||||
/**
|
||||
* get_ipv6_ext_hdrs() - Parses packet and sets IPv6 extension header flags.
|
||||
*
|
||||
* @skb: buffer where extension header data starts in packet
|
||||
* @nh: ipv6 header
|
||||
* @ext_hdrs: flags are stored here
|
||||
*
|
||||
* OFPIEH12_UNREP is set if more than one of a given IPv6 extension header
|
||||
* is unexpectedly encountered. (Two destination options headers may be
|
||||
* expected and would not cause this bit to be set.)
|
||||
*
|
||||
* OFPIEH12_UNSEQ is set if IPv6 extension headers were not in the order
|
||||
* preferred (but not required) by RFC 2460:
|
||||
*
|
||||
* When more than one extension header is used in the same packet, it is
|
||||
* recommended that those headers appear in the following order:
|
||||
* IPv6 header
|
||||
* Hop-by-Hop Options header
|
||||
* Destination Options header
|
||||
* Routing header
|
||||
* Fragment header
|
||||
* Authentication header
|
||||
* Encapsulating Security Payload header
|
||||
* Destination Options header
|
||||
* upper-layer header
|
||||
*/
|
||||
static void get_ipv6_ext_hdrs(struct sk_buff *skb, struct ipv6hdr *nh,
|
||||
u16 *ext_hdrs)
|
||||
{
|
||||
u8 next_type = nh->nexthdr;
|
||||
unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
|
||||
int dest_options_header_count = 0;
|
||||
|
||||
*ext_hdrs = 0;
|
||||
|
||||
while (ipv6_ext_hdr(next_type)) {
|
||||
struct ipv6_opt_hdr _hdr, *hp;
|
||||
|
||||
switch (next_type) {
|
||||
case IPPROTO_NONE:
|
||||
*ext_hdrs |= OFPIEH12_NONEXT;
|
||||
/* stop parsing */
|
||||
return;
|
||||
|
||||
case IPPROTO_ESP:
|
||||
if (*ext_hdrs & OFPIEH12_ESP)
|
||||
*ext_hdrs |= OFPIEH12_UNREP;
|
||||
if ((*ext_hdrs & ~(OFPIEH12_HOP | OFPIEH12_DEST |
|
||||
OFPIEH12_ROUTER | IPPROTO_FRAGMENT |
|
||||
OFPIEH12_AUTH | OFPIEH12_UNREP)) ||
|
||||
dest_options_header_count >= 2) {
|
||||
*ext_hdrs |= OFPIEH12_UNSEQ;
|
||||
}
|
||||
*ext_hdrs |= OFPIEH12_ESP;
|
||||
break;
|
||||
|
||||
case IPPROTO_AH:
|
||||
if (*ext_hdrs & OFPIEH12_AUTH)
|
||||
*ext_hdrs |= OFPIEH12_UNREP;
|
||||
if ((*ext_hdrs &
|
||||
~(OFPIEH12_HOP | OFPIEH12_DEST | OFPIEH12_ROUTER |
|
||||
IPPROTO_FRAGMENT | OFPIEH12_UNREP)) ||
|
||||
dest_options_header_count >= 2) {
|
||||
*ext_hdrs |= OFPIEH12_UNSEQ;
|
||||
}
|
||||
*ext_hdrs |= OFPIEH12_AUTH;
|
||||
break;
|
||||
|
||||
case IPPROTO_DSTOPTS:
|
||||
if (dest_options_header_count == 0) {
|
||||
if (*ext_hdrs &
|
||||
~(OFPIEH12_HOP | OFPIEH12_UNREP))
|
||||
*ext_hdrs |= OFPIEH12_UNSEQ;
|
||||
*ext_hdrs |= OFPIEH12_DEST;
|
||||
} else if (dest_options_header_count == 1) {
|
||||
if (*ext_hdrs &
|
||||
~(OFPIEH12_HOP | OFPIEH12_DEST |
|
||||
OFPIEH12_ROUTER | OFPIEH12_FRAG |
|
||||
OFPIEH12_AUTH | OFPIEH12_ESP |
|
||||
OFPIEH12_UNREP)) {
|
||||
*ext_hdrs |= OFPIEH12_UNSEQ;
|
||||
}
|
||||
} else {
|
||||
*ext_hdrs |= OFPIEH12_UNREP;
|
||||
}
|
||||
dest_options_header_count++;
|
||||
break;
|
||||
|
||||
case IPPROTO_FRAGMENT:
|
||||
if (*ext_hdrs & OFPIEH12_FRAG)
|
||||
*ext_hdrs |= OFPIEH12_UNREP;
|
||||
if ((*ext_hdrs & ~(OFPIEH12_HOP |
|
||||
OFPIEH12_DEST |
|
||||
OFPIEH12_ROUTER |
|
||||
OFPIEH12_UNREP)) ||
|
||||
dest_options_header_count >= 2) {
|
||||
*ext_hdrs |= OFPIEH12_UNSEQ;
|
||||
}
|
||||
*ext_hdrs |= OFPIEH12_FRAG;
|
||||
break;
|
||||
|
||||
case IPPROTO_ROUTING:
|
||||
if (*ext_hdrs & OFPIEH12_ROUTER)
|
||||
*ext_hdrs |= OFPIEH12_UNREP;
|
||||
if ((*ext_hdrs & ~(OFPIEH12_HOP |
|
||||
OFPIEH12_DEST |
|
||||
OFPIEH12_UNREP)) ||
|
||||
dest_options_header_count >= 2) {
|
||||
*ext_hdrs |= OFPIEH12_UNSEQ;
|
||||
}
|
||||
*ext_hdrs |= OFPIEH12_ROUTER;
|
||||
break;
|
||||
|
||||
case IPPROTO_HOPOPTS:
|
||||
if (*ext_hdrs & OFPIEH12_HOP)
|
||||
*ext_hdrs |= OFPIEH12_UNREP;
|
||||
/* OFPIEH12_HOP is set to 1 if a hop-by-hop IPv6
|
||||
* extension header is present as the first
|
||||
* extension header in the packet.
|
||||
*/
|
||||
if (*ext_hdrs == 0)
|
||||
*ext_hdrs |= OFPIEH12_HOP;
|
||||
else
|
||||
*ext_hdrs |= OFPIEH12_UNSEQ;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
|
||||
if (!hp)
|
||||
break;
|
||||
next_type = hp->nexthdr;
|
||||
start += ipv6_optlen(hp);
|
||||
};
|
||||
}
|
||||
|
||||
static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
{
|
||||
unsigned short frag_off;
|
||||
@@ -256,6 +394,8 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
|
||||
|
||||
nh = ipv6_hdr(skb);
|
||||
|
||||
get_ipv6_ext_hdrs(skb, nh, &key->ipv6.exthdrs);
|
||||
|
||||
key->ip.proto = NEXTHDR_NONE;
|
||||
key->ip.tos = ipv6_get_dsfield(nh);
|
||||
key->ip.ttl = nh->hop_limit;
|
||||
|
||||
Reference in New Issue
Block a user