aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2015-01-08 15:31:18 -0500
committerDavid S. Miller <davem@davemloft.net>2015-01-12 16:05:01 -0500
commit3bf3947526c1053ddf2523f261395d682718f56c (patch)
tree5919aa9d9cb34576a14d02d4753390ee71a6a9d6
parenteee2f04b801ebc95da16f91fef029a083ba1a216 (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.c42
-rw-r--r--include/net/vxlan.h7
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
1137bad_flags:
1138 netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
1139 ntohl(vxh->vx_flags), ntohl(vxh->vx_vni));
1140
1127error: 1141error:
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
20struct vxlan_sock; 27struct vxlan_sock;
21typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key); 28typedef void (vxlan_rcv_t)(struct vxlan_sock *vh, struct sk_buff *skb, __be32 key);
22 29