GRE is a somewhat annoying protocol because the header is variable
length. However, it does have a few fields that are always present
so we can make the parsing seem less magical by using a struct for
those fields instead of building it up field by field.
* number of options. */
#define GRE_HEADER_SECTION 4
* number of options. */
#define GRE_HEADER_SECTION 4
+struct gre_base_hdr {
+ __be16 flags;
+ __be16 protocol;
+};
+
struct mutable_config {
struct rcu_head rcu;
struct mutable_config {
struct rcu_head rcu;
const struct mutable_config *mutable)
{
struct iphdr *iph = ip_hdr(skb);
const struct mutable_config *mutable)
{
struct iphdr *iph = ip_hdr(skb);
- __be16 *flags = (__be16 *)(iph + 1);
- __be16 *protocol = flags + 1;
+ struct gre_base_hdr *greh = (struct gre_base_hdr *)(iph + 1);
__be32 *options = (__be32 *)((u8 *)iph + mutable->tunnel_hlen
- GRE_HEADER_SECTION);
__be32 *options = (__be32 *)((u8 *)iph + mutable->tunnel_hlen
- GRE_HEADER_SECTION);
- *protocol = htons(ETH_P_TEB);
- *flags = 0;
+ greh->protocol = htons(ETH_P_TEB);
+ greh->flags = 0;
/* Work backwards over the options so the checksum is last. */
if (mutable->port_config.out_key ||
mutable->port_config.flags & GRE_F_OUT_KEY_ACTION) {
/* Work backwards over the options so the checksum is last. */
if (mutable->port_config.out_key ||
mutable->port_config.flags & GRE_F_OUT_KEY_ACTION) {
+ greh->flags |= GRE_KEY;
if (mutable->port_config.flags & GRE_F_OUT_KEY_ACTION)
*options = OVS_CB(skb)->tun_id;
if (mutable->port_config.flags & GRE_F_OUT_KEY_ACTION)
*options = OVS_CB(skb)->tun_id;
}
if (mutable->port_config.flags & GRE_F_OUT_CSUM) {
}
if (mutable->port_config.flags & GRE_F_OUT_CSUM) {
+ greh->flags |= GRE_CSUM;
*options = 0;
*(__sum16 *)options = csum_fold(skb_checksum(skb,
*options = 0;
*(__sum16 *)options = csum_fold(skb_checksum(skb,
static int parse_gre_header(struct iphdr *iph, __be16 *flags, __be32 *key)
{
/* IP and ICMP protocol handlers check that the IHL is valid. */
static int parse_gre_header(struct iphdr *iph, __be16 *flags, __be32 *key)
{
/* IP and ICMP protocol handlers check that the IHL is valid. */
- __be16 *flagsp = (__be16 *)((u8 *)iph + (iph->ihl << 2));
- __be16 *protocol = flagsp + 1;
- __be32 *options = (__be32 *)(protocol + 1);
+ struct gre_base_hdr *greh = (struct gre_base_hdr *)((u8 *)iph + (iph->ihl << 2));
+ __be32 *options = (__be32 *)(greh + 1);
- if (*flags & (GRE_VERSION | GRE_ROUTING))
+ if (greh->flags & (GRE_VERSION | GRE_ROUTING))
- if (*protocol != htons(ETH_P_TEB))
+ if (greh->protocol != htons(ETH_P_TEB))
return -EINVAL;
hdr_len = GRE_HEADER_SECTION;
return -EINVAL;
hdr_len = GRE_HEADER_SECTION;
- if (*flags & GRE_CSUM) {
+ if (greh->flags & GRE_CSUM) {
hdr_len += GRE_HEADER_SECTION;
options++;
}
hdr_len += GRE_HEADER_SECTION;
options++;
}
- if (*flags & GRE_KEY) {
+ if (greh->flags & GRE_KEY) {
hdr_len += GRE_HEADER_SECTION;
*key = *options;
hdr_len += GRE_HEADER_SECTION;
*key = *options;
+ if (greh->flags & GRE_SEQ)
hdr_len += GRE_HEADER_SECTION;
return hdr_len;
hdr_len += GRE_HEADER_SECTION;
return hdr_len;