diff options
author | Tom Herbert <therbert@google.com> | 2015-01-08 15:31:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-12 16:05:01 -0500 |
commit | 3bf3947526c1053ddf2523f261395d682718f56c (patch) | |
tree | 5919aa9d9cb34576a14d02d4753390ee71a6a9d6 | |
parent | eee2f04b801ebc95da16f91fef029a083ba1a216 (diff) |
vxlan: Improve support for header flags
This patch cleans up the header flags of VXLAN in anticipation of
defining some new ones:
- Move header related definitions from vxlan.c to vxlan.h
- Change VXLAN_FLAGS to be VXLAN_HF_VNI (only currently defined flag)
- Move check for unknown flags to after we find vxlan_sock, this
assumes that some flags may be processed based on tunnel
configuration
- Add a comment about why the stack treating unknown set flags as an
error instead of ignoring them
Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/vxlan.c | 42 | ||||
-rw-r--r-- | include/net/vxlan.h | 7 |
2 files changed, 35 insertions, 14 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 2ab0922af0b4..3a18d8ed89ca 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -61,12 +61,6 @@ | |||
61 | #define FDB_AGE_DEFAULT 300 /* 5 min */ | 61 | #define FDB_AGE_DEFAULT 300 /* 5 min */ |
62 | #define FDB_AGE_INTERVAL (10 * HZ) /* rescan interval */ | 62 | #define FDB_AGE_INTERVAL (10 * HZ) /* rescan interval */ |
63 | 63 | ||
64 | #define VXLAN_N_VID (1u << 24) | ||
65 | #define VXLAN_VID_MASK (VXLAN_N_VID - 1) | ||
66 | #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) | ||
67 | |||
68 | #define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */ | ||
69 | |||
70 | /* UDP port for VXLAN traffic. | 64 | /* UDP port for VXLAN traffic. |
71 | * The IANA assigned port is 4789, but the Linux default is 8472 | 65 | * The IANA assigned port is 4789, but the Linux default is 8472 |
72 | * for compatibility with early adopters. | 66 | * for compatibility with early adopters. |
@@ -1095,18 +1089,21 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) | |||
1095 | { | 1089 | { |
1096 | struct vxlan_sock *vs; | 1090 | struct vxlan_sock *vs; |
1097 | struct vxlanhdr *vxh; | 1091 | struct vxlanhdr *vxh; |
1092 | u32 flags, vni; | ||
1098 | 1093 | ||
1099 | /* Need Vxlan and inner Ethernet header to be present */ | 1094 | /* Need Vxlan and inner Ethernet header to be present */ |
1100 | if (!pskb_may_pull(skb, VXLAN_HLEN)) | 1095 | if (!pskb_may_pull(skb, VXLAN_HLEN)) |
1101 | goto error; | 1096 | goto error; |
1102 | 1097 | ||
1103 | /* Return packets with reserved bits set */ | ||
1104 | vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1); | 1098 | vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1); |
1105 | if (vxh->vx_flags != htonl(VXLAN_FLAGS) || | 1099 | flags = ntohl(vxh->vx_flags); |
1106 | (vxh->vx_vni & htonl(0xff))) { | 1100 | vni = ntohl(vxh->vx_vni); |
1107 | netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n", | 1101 | |
1108 | ntohl(vxh->vx_flags), ntohl(vxh->vx_vni)); | 1102 | if (flags & VXLAN_HF_VNI) { |
1109 | goto error; | 1103 | flags &= ~VXLAN_HF_VNI; |
1104 | } else { | ||
1105 | /* VNI flag always required to be set */ | ||
1106 | goto bad_flags; | ||
1110 | } | 1107 | } |
1111 | 1108 | ||
1112 | if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) | 1109 | if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) |
@@ -1116,6 +1113,19 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) | |||
1116 | if (!vs) | 1113 | if (!vs) |
1117 | goto drop; | 1114 | goto drop; |
1118 | 1115 | ||
1116 | if (flags || (vni & 0xff)) { | ||
1117 | /* If there are any unprocessed flags remaining treat | ||
1118 | * this as a malformed packet. This behavior diverges from | ||
1119 | * VXLAN RFC (RFC7348) which stipulates that bits in reserved | ||
1120 | * in reserved fields are to be ignored. The approach here | ||
1121 | * maintains compatbility with previous stack code, and also | ||
1122 | * is more robust and provides a little more security in | ||
1123 | * adding extensions to VXLAN. | ||
1124 | */ | ||
1125 | |||
1126 | goto bad_flags; | ||
1127 | } | ||
1128 | |||
1119 | vs->rcv(vs, skb, vxh->vx_vni); | 1129 | vs->rcv(vs, skb, vxh->vx_vni); |
1120 | return 0; | 1130 | return 0; |
1121 | 1131 | ||
@@ -1124,6 +1134,10 @@ drop: | |||
1124 | kfree_skb(skb); | 1134 | kfree_skb(skb); |
1125 | return 0; | 1135 | return 0; |
1126 | 1136 | ||
1137 | bad_flags: | ||
1138 | netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n", | ||
1139 | ntohl(vxh->vx_flags), ntohl(vxh->vx_vni)); | ||
1140 | |||
1127 | error: | 1141 | error: |
1128 | /* Return non vxlan pkt */ | 1142 | /* Return non vxlan pkt */ |
1129 | return 1; | 1143 | return 1; |
@@ -1563,7 +1577,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs, | |||
1563 | } | 1577 | } |
1564 | 1578 | ||
1565 | vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); | 1579 | vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); |
1566 | vxh->vx_flags = htonl(VXLAN_FLAGS); | 1580 | vxh->vx_flags = htonl(VXLAN_HF_VNI); |
1567 | vxh->vx_vni = vni; | 1581 | vxh->vx_vni = vni; |
1568 | 1582 | ||
1569 | skb_set_inner_protocol(skb, htons(ETH_P_TEB)); | 1583 | skb_set_inner_protocol(skb, htons(ETH_P_TEB)); |
@@ -1607,7 +1621,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, | |||
1607 | return -ENOMEM; | 1621 | return -ENOMEM; |
1608 | 1622 | ||
1609 | vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); | 1623 | vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); |
1610 | vxh->vx_flags = htonl(VXLAN_FLAGS); | 1624 | vxh->vx_flags = htonl(VXLAN_HF_VNI); |
1611 | vxh->vx_vni = vni; | 1625 | vxh->vx_vni = vni; |
1612 | 1626 | ||
1613 | skb_set_inner_protocol(skb, htons(ETH_P_TEB)); | 1627 | skb_set_inner_protocol(skb, htons(ETH_P_TEB)); |
diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 903461aa5644..a0d80736224f 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h | |||
@@ -17,6 +17,13 @@ struct vxlanhdr { | |||
17 | __be32 vx_vni; | 17 | __be32 vx_vni; |
18 | }; | 18 | }; |
19 | 19 | ||
20 | /* VXLAN header flags. */ | ||
21 | #define VXLAN_HF_VNI 0x08000000 | ||
22 | |||
23 | #define VXLAN_N_VID (1u << 24) | ||
24 | #define VXLAN_VID_MASK (VXLAN_N_VID - 1) | ||
25 | #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) | ||
26 | |||
20 | struct vxlan_sock; | 27 | struct vxlan_sock; |
21 | typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key); | 28 | typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key); |
22 | 29 | ||