diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-08-19 14:23:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-20 03:15:43 -0400 |
commit | 49560532d74962608526121ecb0d2ad0c87f9cc0 (patch) | |
tree | dc7a6bbdda48791d0528cc67c5abe06c64d6bb1a | |
parent | 012a5729ff933ecd07e7470a65d84577aef9ae03 (diff) |
vxlan: Factor out vxlan send api.
Following patch allows more code sharing between vxlan and ovs-vxlan.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/vxlan.c | 91 | ||||
-rw-r--r-- | include/net/vxlan.h | 8 |
2 files changed, 62 insertions, 37 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index aab927b92fb3..f3496e995302 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -1082,11 +1082,8 @@ static void vxlan_sock_put(struct sk_buff *skb) | |||
1082 | } | 1082 | } |
1083 | 1083 | ||
1084 | /* On transmit, associate with the tunnel socket */ | 1084 | /* On transmit, associate with the tunnel socket */ |
1085 | static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb) | 1085 | static void vxlan_set_owner(struct sock *sk, struct sk_buff *skb) |
1086 | { | 1086 | { |
1087 | struct vxlan_dev *vxlan = netdev_priv(dev); | ||
1088 | struct sock *sk = vxlan->vn_sock->sock->sk; | ||
1089 | |||
1090 | skb_orphan(skb); | 1087 | skb_orphan(skb); |
1091 | sock_hold(sk); | 1088 | sock_hold(sk); |
1092 | skb->sk = sk; | 1089 | skb->sk = sk; |
@@ -1098,9 +1095,9 @@ static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb) | |||
1098 | * better and maybe available from hardware | 1095 | * better and maybe available from hardware |
1099 | * secondary choice is to use jhash on the Ethernet header | 1096 | * secondary choice is to use jhash on the Ethernet header |
1100 | */ | 1097 | */ |
1101 | static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb) | 1098 | __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb) |
1102 | { | 1099 | { |
1103 | unsigned int range = (vxlan->port_max - vxlan->port_min) + 1; | 1100 | unsigned int range = (port_max - port_min) + 1; |
1104 | u32 hash; | 1101 | u32 hash; |
1105 | 1102 | ||
1106 | hash = skb_get_rxhash(skb); | 1103 | hash = skb_get_rxhash(skb); |
@@ -1108,8 +1105,9 @@ static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb) | |||
1108 | hash = jhash(skb->data, 2 * ETH_ALEN, | 1105 | hash = jhash(skb->data, 2 * ETH_ALEN, |
1109 | (__force u32) skb->protocol); | 1106 | (__force u32) skb->protocol); |
1110 | 1107 | ||
1111 | return htons((((u64) hash * range) >> 32) + vxlan->port_min); | 1108 | return htons((((u64) hash * range) >> 32) + port_min); |
1112 | } | 1109 | } |
1110 | EXPORT_SYMBOL_GPL(vxlan_src_port); | ||
1113 | 1111 | ||
1114 | static int handle_offloads(struct sk_buff *skb) | 1112 | static int handle_offloads(struct sk_buff *skb) |
1115 | { | 1113 | { |
@@ -1125,6 +1123,45 @@ static int handle_offloads(struct sk_buff *skb) | |||
1125 | return 0; | 1123 | return 0; |
1126 | } | 1124 | } |
1127 | 1125 | ||
1126 | int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs, | ||
1127 | struct rtable *rt, struct sk_buff *skb, | ||
1128 | __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, | ||
1129 | __be16 src_port, __be16 dst_port, __be32 vni) | ||
1130 | { | ||
1131 | struct vxlanhdr *vxh; | ||
1132 | struct udphdr *uh; | ||
1133 | int err; | ||
1134 | |||
1135 | if (!skb->encapsulation) { | ||
1136 | skb_reset_inner_headers(skb); | ||
1137 | skb->encapsulation = 1; | ||
1138 | } | ||
1139 | |||
1140 | vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); | ||
1141 | vxh->vx_flags = htonl(VXLAN_FLAGS); | ||
1142 | vxh->vx_vni = vni; | ||
1143 | |||
1144 | __skb_push(skb, sizeof(*uh)); | ||
1145 | skb_reset_transport_header(skb); | ||
1146 | uh = udp_hdr(skb); | ||
1147 | |||
1148 | uh->dest = dst_port; | ||
1149 | uh->source = src_port; | ||
1150 | |||
1151 | uh->len = htons(skb->len); | ||
1152 | uh->check = 0; | ||
1153 | |||
1154 | vxlan_set_owner(vs->sock->sk, skb); | ||
1155 | |||
1156 | err = handle_offloads(skb); | ||
1157 | if (err) | ||
1158 | return err; | ||
1159 | |||
1160 | return iptunnel_xmit(net, rt, skb, src, dst, | ||
1161 | IPPROTO_UDP, tos, ttl, df); | ||
1162 | } | ||
1163 | EXPORT_SYMBOL_GPL(vxlan_xmit_skb); | ||
1164 | |||
1128 | /* Bypass encapsulation if the destination is local */ | 1165 | /* Bypass encapsulation if the destination is local */ |
1129 | static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, | 1166 | static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, |
1130 | struct vxlan_dev *dst_vxlan) | 1167 | struct vxlan_dev *dst_vxlan) |
@@ -1162,8 +1199,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
1162 | struct vxlan_dev *vxlan = netdev_priv(dev); | 1199 | struct vxlan_dev *vxlan = netdev_priv(dev); |
1163 | struct rtable *rt; | 1200 | struct rtable *rt; |
1164 | const struct iphdr *old_iph; | 1201 | const struct iphdr *old_iph; |
1165 | struct vxlanhdr *vxh; | ||
1166 | struct udphdr *uh; | ||
1167 | struct flowi4 fl4; | 1202 | struct flowi4 fl4; |
1168 | __be32 dst; | 1203 | __be32 dst; |
1169 | __be16 src_port, dst_port; | 1204 | __be16 src_port, dst_port; |
@@ -1185,11 +1220,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
1185 | goto drop; | 1220 | goto drop; |
1186 | } | 1221 | } |
1187 | 1222 | ||
1188 | if (!skb->encapsulation) { | ||
1189 | skb_reset_inner_headers(skb); | ||
1190 | skb->encapsulation = 1; | ||
1191 | } | ||
1192 | |||
1193 | /* Need space for new headers (invalidates iph ptr) */ | 1223 | /* Need space for new headers (invalidates iph ptr) */ |
1194 | if (skb_cow_head(skb, VXLAN_HEADROOM)) | 1224 | if (skb_cow_head(skb, VXLAN_HEADROOM)) |
1195 | goto drop; | 1225 | goto drop; |
@@ -1204,7 +1234,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
1204 | if (tos == 1) | 1234 | if (tos == 1) |
1205 | tos = ip_tunnel_get_dsfield(old_iph, skb); | 1235 | tos = ip_tunnel_get_dsfield(old_iph, skb); |
1206 | 1236 | ||
1207 | src_port = vxlan_src_port(vxlan, skb); | 1237 | src_port = vxlan_src_port(vxlan->port_min, vxlan->port_max, skb); |
1208 | 1238 | ||
1209 | memset(&fl4, 0, sizeof(fl4)); | 1239 | memset(&fl4, 0, sizeof(fl4)); |
1210 | fl4.flowi4_oif = rdst->remote_ifindex; | 1240 | fl4.flowi4_oif = rdst->remote_ifindex; |
@@ -1221,9 +1251,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
1221 | 1251 | ||
1222 | if (rt->dst.dev == dev) { | 1252 | if (rt->dst.dev == dev) { |
1223 | netdev_dbg(dev, "circular route to %pI4\n", &dst); | 1253 | netdev_dbg(dev, "circular route to %pI4\n", &dst); |
1224 | ip_rt_put(rt); | ||
1225 | dev->stats.collisions++; | 1254 | dev->stats.collisions++; |
1226 | goto tx_error; | 1255 | goto rt_tx_error; |
1227 | } | 1256 | } |
1228 | 1257 | ||
1229 | /* Bypass encapsulation if the destination is local */ | 1258 | /* Bypass encapsulation if the destination is local */ |
@@ -1238,30 +1267,16 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, | |||
1238 | vxlan_encap_bypass(skb, vxlan, dst_vxlan); | 1267 | vxlan_encap_bypass(skb, vxlan, dst_vxlan); |
1239 | return; | 1268 | return; |
1240 | } | 1269 | } |
1241 | vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); | ||
1242 | vxh->vx_flags = htonl(VXLAN_FLAGS); | ||
1243 | vxh->vx_vni = htonl(vni << 8); | ||
1244 | |||
1245 | __skb_push(skb, sizeof(*uh)); | ||
1246 | skb_reset_transport_header(skb); | ||
1247 | uh = udp_hdr(skb); | ||
1248 | |||
1249 | uh->dest = dst_port; | ||
1250 | uh->source = src_port; | ||
1251 | |||
1252 | uh->len = htons(skb->len); | ||
1253 | uh->check = 0; | ||
1254 | |||
1255 | vxlan_set_owner(dev, skb); | ||
1256 | |||
1257 | if (handle_offloads(skb)) | ||
1258 | goto drop; | ||
1259 | 1270 | ||
1260 | tos = ip_tunnel_ecn_encap(tos, old_iph, skb); | 1271 | tos = ip_tunnel_ecn_encap(tos, old_iph, skb); |
1261 | ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); | 1272 | ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); |
1262 | 1273 | ||
1263 | err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, dst, | 1274 | err = vxlan_xmit_skb(dev_net(dev), vxlan->vn_sock, rt, skb, |
1264 | IPPROTO_UDP, tos, ttl, df); | 1275 | fl4.saddr, dst, tos, ttl, df, |
1276 | src_port, dst_port, htonl(vni << 8)); | ||
1277 | |||
1278 | if (err < 0) | ||
1279 | goto rt_tx_error; | ||
1265 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); | 1280 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); |
1266 | 1281 | ||
1267 | return; | 1282 | return; |
@@ -1270,6 +1285,8 @@ drop: | |||
1270 | dev->stats.tx_dropped++; | 1285 | dev->stats.tx_dropped++; |
1271 | goto tx_free; | 1286 | goto tx_free; |
1272 | 1287 | ||
1288 | rt_tx_error: | ||
1289 | ip_rt_put(rt); | ||
1273 | tx_error: | 1290 | tx_error: |
1274 | dev->stats.tx_errors++; | 1291 | dev->stats.tx_errors++; |
1275 | tx_free: | 1292 | tx_free: |
diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 43de27585cb0..ad342e3688a0 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h | |||
@@ -28,4 +28,12 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, | |||
28 | bool no_share); | 28 | bool no_share); |
29 | 29 | ||
30 | void vxlan_sock_release(struct vxlan_sock *vs); | 30 | void vxlan_sock_release(struct vxlan_sock *vs); |
31 | |||
32 | int vxlan_xmit_skb(struct net *net, struct vxlan_sock *vs, | ||
33 | struct rtable *rt, struct sk_buff *skb, | ||
34 | __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, | ||
35 | __be16 src_port, __be16 dst_port, __be32 vni); | ||
36 | |||
37 | __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb); | ||
38 | |||
31 | #endif | 39 | #endif |