aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorWenyu Zhang <wenyuz@vmware.com>2014-11-06 09:51:24 -0500
committerPravin B Shelar <pshelar@nicira.com>2014-11-09 21:58:44 -0500
commit8f0aad6f35f7e8b3118b7b8a65e8e76b135cc4cb (patch)
tree5f3dd8374c3c1584cb2b516f4191e70b82472f68 /net/openvswitch
parent9ba559d9ca3711940be3e7207dac13c4f0654d43 (diff)
openvswitch: Extend packet attribute for egress tunnel info
OVS vswitch has extended IPFIX exporter to export tunnel headers to improve network visibility. To export this information userspace needs to know egress tunnel for given packet. By extending packet attributes datapath can export egress tunnel info for given packet. So that userspace can ask for egress tunnel info in userspace action. This information is used to build IPFIX data for given flow. Signed-off-by: Wenyu Zhang <wenyuz@vmware.com> Acked-by: Romain Lenglet <rlenglet@vmware.com> Acked-by: Ben Pfaff <blp@nicira.com> Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/actions.c19
-rw-r--r--net/openvswitch/datapath.c21
-rw-r--r--net/openvswitch/datapath.h2
-rw-r--r--net/openvswitch/flow.h62
-rw-r--r--net/openvswitch/flow_netlink.c54
-rw-r--r--net/openvswitch/flow_netlink.h3
-rw-r--r--net/openvswitch/vport-geneve.c21
-rw-r--r--net/openvswitch/vport-gre.c12
-rw-r--r--net/openvswitch/vport-vxlan.c24
-rw-r--r--net/openvswitch/vport.c61
-rw-r--r--net/openvswitch/vport.h14
11 files changed, 262 insertions, 31 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index f7e589159e4a..ceb618cf1292 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -564,6 +564,7 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
564static int output_userspace(struct datapath *dp, struct sk_buff *skb, 564static int output_userspace(struct datapath *dp, struct sk_buff *skb,
565 struct sw_flow_key *key, const struct nlattr *attr) 565 struct sw_flow_key *key, const struct nlattr *attr)
566{ 566{
567 struct ovs_tunnel_info info;
567 struct dp_upcall_info upcall; 568 struct dp_upcall_info upcall;
568 const struct nlattr *a; 569 const struct nlattr *a;
569 int rem; 570 int rem;
@@ -572,6 +573,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
572 upcall.key = key; 573 upcall.key = key;
573 upcall.userdata = NULL; 574 upcall.userdata = NULL;
574 upcall.portid = 0; 575 upcall.portid = 0;
576 upcall.egress_tun_info = NULL;
575 577
576 for (a = nla_data(attr), rem = nla_len(attr); rem > 0; 578 for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
577 a = nla_next(a, &rem)) { 579 a = nla_next(a, &rem)) {
@@ -583,7 +585,24 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
583 case OVS_USERSPACE_ATTR_PID: 585 case OVS_USERSPACE_ATTR_PID:
584 upcall.portid = nla_get_u32(a); 586 upcall.portid = nla_get_u32(a);
585 break; 587 break;
588
589 case OVS_USERSPACE_ATTR_EGRESS_TUN_PORT: {
590 /* Get out tunnel info. */
591 struct vport *vport;
592
593 vport = ovs_vport_rcu(dp, nla_get_u32(a));
594 if (vport) {
595 int err;
596
597 err = ovs_vport_get_egress_tun_info(vport, skb,
598 &info);
599 if (!err)
600 upcall.egress_tun_info = &info;
601 }
602 break;
586 } 603 }
604
605 } /* End of switch. */
587 } 606 }
588 607
589 return ovs_dp_upcall(dp, skb, &upcall); 608 return ovs_dp_upcall(dp, skb, &upcall);
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 6cfb44f3a7f0..c2ac340e19fb 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -274,6 +274,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
274 upcall.key = key; 274 upcall.key = key;
275 upcall.userdata = NULL; 275 upcall.userdata = NULL;
276 upcall.portid = ovs_vport_find_upcall_portid(p, skb); 276 upcall.portid = ovs_vport_find_upcall_portid(p, skb);
277 upcall.egress_tun_info = NULL;
277 error = ovs_dp_upcall(dp, skb, &upcall); 278 error = ovs_dp_upcall(dp, skb, &upcall);
278 if (unlikely(error)) 279 if (unlikely(error))
279 kfree_skb(skb); 280 kfree_skb(skb);
@@ -375,7 +376,7 @@ static int queue_gso_packets(struct datapath *dp, struct sk_buff *skb,
375 return err; 376 return err;
376} 377}
377 378
378static size_t upcall_msg_size(const struct nlattr *userdata, 379static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
379 unsigned int hdrlen) 380 unsigned int hdrlen)
380{ 381{
381 size_t size = NLMSG_ALIGN(sizeof(struct ovs_header)) 382 size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
@@ -383,8 +384,12 @@ static size_t upcall_msg_size(const struct nlattr *userdata,
383 + nla_total_size(ovs_key_attr_size()); /* OVS_PACKET_ATTR_KEY */ 384 + nla_total_size(ovs_key_attr_size()); /* OVS_PACKET_ATTR_KEY */
384 385
385 /* OVS_PACKET_ATTR_USERDATA */ 386 /* OVS_PACKET_ATTR_USERDATA */
386 if (userdata) 387 if (upcall_info->userdata)
387 size += NLA_ALIGN(userdata->nla_len); 388 size += NLA_ALIGN(upcall_info->userdata->nla_len);
389
390 /* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
391 if (upcall_info->egress_tun_info)
392 size += nla_total_size(ovs_tun_key_attr_size());
388 393
389 return size; 394 return size;
390} 395}
@@ -440,7 +445,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
440 else 445 else
441 hlen = skb->len; 446 hlen = skb->len;
442 447
443 len = upcall_msg_size(upcall_info->userdata, hlen); 448 len = upcall_msg_size(upcall_info, hlen);
444 user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC); 449 user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
445 if (!user_skb) { 450 if (!user_skb) {
446 err = -ENOMEM; 451 err = -ENOMEM;
@@ -461,6 +466,14 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
461 nla_len(upcall_info->userdata), 466 nla_len(upcall_info->userdata),
462 nla_data(upcall_info->userdata)); 467 nla_data(upcall_info->userdata));
463 468
469 if (upcall_info->egress_tun_info) {
470 nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
471 err = ovs_nla_put_egress_tunnel_key(user_skb,
472 upcall_info->egress_tun_info);
473 BUG_ON(err);
474 nla_nest_end(user_skb, nla);
475 }
476
464 /* Only reserve room for attribute header, packet data is added 477 /* Only reserve room for attribute header, packet data is added
465 * in skb_zerocopy() */ 478 * in skb_zerocopy() */
466 if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) { 479 if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index 1c56a80d6677..2bc577bf9b31 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -114,12 +114,14 @@ struct ovs_skb_cb {
114 * @pid: Netlink PID to which packet should be sent. If @pid is 0 then no 114 * @pid: Netlink PID to which packet should be sent. If @pid is 0 then no
115 * packet is sent and the packet is accounted in the datapath's @n_lost 115 * packet is sent and the packet is accounted in the datapath's @n_lost
116 * counter. 116 * counter.
117 * @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY.
117 */ 118 */
118struct dp_upcall_info { 119struct dp_upcall_info {
119 u8 cmd; 120 u8 cmd;
120 const struct sw_flow_key *key; 121 const struct sw_flow_key *key;
121 const struct nlattr *userdata; 122 const struct nlattr *userdata;
122 u32 portid; 123 u32 portid;
124 const struct ovs_tunnel_info *egress_tun_info;
123}; 125};
124 126
125/** 127/**
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index 4962bee81a11..543b358ee57f 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -37,8 +37,8 @@ struct sk_buff;
37 37
38/* Used to memset ovs_key_ipv4_tunnel padding. */ 38/* Used to memset ovs_key_ipv4_tunnel padding. */
39#define OVS_TUNNEL_KEY_SIZE \ 39#define OVS_TUNNEL_KEY_SIZE \
40 (offsetof(struct ovs_key_ipv4_tunnel, ipv4_ttl) + \ 40 (offsetof(struct ovs_key_ipv4_tunnel, tp_dst) + \
41 FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, ipv4_ttl)) 41 FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, tp_dst))
42 42
43struct ovs_key_ipv4_tunnel { 43struct ovs_key_ipv4_tunnel {
44 __be64 tun_id; 44 __be64 tun_id;
@@ -47,6 +47,8 @@ struct ovs_key_ipv4_tunnel {
47 __be16 tun_flags; 47 __be16 tun_flags;
48 u8 ipv4_tos; 48 u8 ipv4_tos;
49 u8 ipv4_ttl; 49 u8 ipv4_ttl;
50 __be16 tp_src;
51 __be16 tp_dst;
50} __packed __aligned(4); /* Minimize padding. */ 52} __packed __aligned(4); /* Minimize padding. */
51 53
52struct ovs_tunnel_info { 54struct ovs_tunnel_info {
@@ -64,27 +66,59 @@ struct ovs_tunnel_info {
64 FIELD_SIZEOF(struct sw_flow_key, tun_opts) - \ 66 FIELD_SIZEOF(struct sw_flow_key, tun_opts) - \
65 opt_len)) 67 opt_len))
66 68
67static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, 69static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
68 const struct iphdr *iph, 70 __be32 saddr, __be32 daddr,
69 __be64 tun_id, __be16 tun_flags, 71 u8 tos, u8 ttl,
70 struct geneve_opt *opts, 72 __be16 tp_src,
71 u8 opts_len) 73 __be16 tp_dst,
74 __be64 tun_id,
75 __be16 tun_flags,
76 struct geneve_opt *opts,
77 u8 opts_len)
72{ 78{
73 tun_info->tunnel.tun_id = tun_id; 79 tun_info->tunnel.tun_id = tun_id;
74 tun_info->tunnel.ipv4_src = iph->saddr; 80 tun_info->tunnel.ipv4_src = saddr;
75 tun_info->tunnel.ipv4_dst = iph->daddr; 81 tun_info->tunnel.ipv4_dst = daddr;
76 tun_info->tunnel.ipv4_tos = iph->tos; 82 tun_info->tunnel.ipv4_tos = tos;
77 tun_info->tunnel.ipv4_ttl = iph->ttl; 83 tun_info->tunnel.ipv4_ttl = ttl;
78 tun_info->tunnel.tun_flags = tun_flags; 84 tun_info->tunnel.tun_flags = tun_flags;
79 85
80 /* clear struct padding. */ 86 /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of
81 memset((unsigned char *)&tun_info->tunnel + OVS_TUNNEL_KEY_SIZE, 0, 87 * the upper tunnel are used.
82 sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE); 88 * E.g: GRE over IPSEC, the tp_src and tp_port are zero.
89 */
90 tun_info->tunnel.tp_src = tp_src;
91 tun_info->tunnel.tp_dst = tp_dst;
92
93 /* Clear struct padding. */
94 if (sizeof(tun_info->tunnel) != OVS_TUNNEL_KEY_SIZE)
95 memset((unsigned char *)&tun_info->tunnel + OVS_TUNNEL_KEY_SIZE,
96 0, sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE);
83 97
84 tun_info->options = opts; 98 tun_info->options = opts;
85 tun_info->options_len = opts_len; 99 tun_info->options_len = opts_len;
86} 100}
87 101
102static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info,
103 const struct iphdr *iph,
104 __be16 tp_src,
105 __be16 tp_dst,
106 __be64 tun_id,
107 __be16 tun_flags,
108 struct geneve_opt *opts,
109 u8 opts_len)
110{
111 __ovs_flow_tun_info_init(tun_info, iph->saddr, iph->daddr,
112 iph->tos, iph->ttl,
113 tp_src, tp_dst,
114 tun_id, tun_flags,
115 opts, opts_len);
116}
117
118#define OVS_SW_FLOW_KEY_METADATA_SIZE \
119 (offsetof(struct sw_flow_key, recirc_id) + \
120 FIELD_SIZEOF(struct sw_flow_key, recirc_id))
121
88struct sw_flow_key { 122struct sw_flow_key {
89 u8 tun_opts[255]; 123 u8 tun_opts[255];
90 u8 tun_opts_len; 124 u8 tun_opts_len;
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index ed3109761827..98a3e96b7d93 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -245,6 +245,24 @@ static bool match_validate(const struct sw_flow_match *match,
245 return true; 245 return true;
246} 246}
247 247
248size_t ovs_tun_key_attr_size(void)
249{
250 /* Whenever adding new OVS_TUNNEL_KEY_ FIELDS, we should consider
251 * updating this function.
252 */
253 return nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */
254 + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
255 + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
256 + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
257 + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
258 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
259 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
260 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
261 + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
262 + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */
263 + nla_total_size(2); /* OVS_TUNNEL_KEY_ATTR_TP_DST */
264}
265
248size_t ovs_key_attr_size(void) 266size_t ovs_key_attr_size(void)
249{ 267{
250 /* Whenever adding new OVS_KEY_ FIELDS, we should consider 268 /* Whenever adding new OVS_KEY_ FIELDS, we should consider
@@ -254,15 +272,7 @@ size_t ovs_key_attr_size(void)
254 272
255 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ 273 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
256 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ 274 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
257 + nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */ 275 + ovs_tun_key_attr_size()
258 + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
259 + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
260 + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */
261 + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */
262 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
263 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */
264 + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */
265 + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */
266 + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */ 276 + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */
267 + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ 277 + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */
268 + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */ 278 + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */
@@ -393,6 +403,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
393 [OVS_TUNNEL_KEY_ATTR_TTL] = 1, 403 [OVS_TUNNEL_KEY_ATTR_TTL] = 1,
394 [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0, 404 [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0,
395 [OVS_TUNNEL_KEY_ATTR_CSUM] = 0, 405 [OVS_TUNNEL_KEY_ATTR_CSUM] = 0,
406 [OVS_TUNNEL_KEY_ATTR_TP_SRC] = sizeof(u16),
407 [OVS_TUNNEL_KEY_ATTR_TP_DST] = sizeof(u16),
396 [OVS_TUNNEL_KEY_ATTR_OAM] = 0, 408 [OVS_TUNNEL_KEY_ATTR_OAM] = 0,
397 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1, 409 [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = -1,
398 }; 410 };
@@ -440,6 +452,14 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr,
440 case OVS_TUNNEL_KEY_ATTR_CSUM: 452 case OVS_TUNNEL_KEY_ATTR_CSUM:
441 tun_flags |= TUNNEL_CSUM; 453 tun_flags |= TUNNEL_CSUM;
442 break; 454 break;
455 case OVS_TUNNEL_KEY_ATTR_TP_SRC:
456 SW_FLOW_KEY_PUT(match, tun_key.tp_src,
457 nla_get_be16(a), is_mask);
458 break;
459 case OVS_TUNNEL_KEY_ATTR_TP_DST:
460 SW_FLOW_KEY_PUT(match, tun_key.tp_dst,
461 nla_get_be16(a), is_mask);
462 break;
443 case OVS_TUNNEL_KEY_ATTR_OAM: 463 case OVS_TUNNEL_KEY_ATTR_OAM:
444 tun_flags |= TUNNEL_OAM; 464 tun_flags |= TUNNEL_OAM;
445 break; 465 break;
@@ -548,6 +568,12 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
548 if ((output->tun_flags & TUNNEL_CSUM) && 568 if ((output->tun_flags & TUNNEL_CSUM) &&
549 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM)) 569 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
550 return -EMSGSIZE; 570 return -EMSGSIZE;
571 if (output->tp_src &&
572 nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_SRC, output->tp_src))
573 return -EMSGSIZE;
574 if (output->tp_dst &&
575 nla_put_be16(skb, OVS_TUNNEL_KEY_ATTR_TP_DST, output->tp_dst))
576 return -EMSGSIZE;
551 if ((output->tun_flags & TUNNEL_OAM) && 577 if ((output->tun_flags & TUNNEL_OAM) &&
552 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM)) 578 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
553 return -EMSGSIZE; 579 return -EMSGSIZE;
@@ -559,7 +585,6 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb,
559 return 0; 585 return 0;
560} 586}
561 587
562
563static int ipv4_tun_to_nlattr(struct sk_buff *skb, 588static int ipv4_tun_to_nlattr(struct sk_buff *skb,
564 const struct ovs_key_ipv4_tunnel *output, 589 const struct ovs_key_ipv4_tunnel *output,
565 const struct geneve_opt *tun_opts, 590 const struct geneve_opt *tun_opts,
@@ -580,6 +605,14 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb,
580 return 0; 605 return 0;
581} 606}
582 607
608int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb,
609 const struct ovs_tunnel_info *egress_tun_info)
610{
611 return __ipv4_tun_to_nlattr(skb, &egress_tun_info->tunnel,
612 egress_tun_info->options,
613 egress_tun_info->options_len);
614}
615
583static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, 616static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
584 const struct nlattr **a, bool is_mask) 617 const struct nlattr **a, bool is_mask)
585{ 618{
@@ -1653,6 +1686,7 @@ static int validate_userspace(const struct nlattr *attr)
1653 static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = { 1686 static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
1654 [OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 }, 1687 [OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
1655 [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC }, 1688 [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
1689 [OVS_USERSPACE_ATTR_EGRESS_TUN_PORT] = {.type = NLA_U32 },
1656 }; 1690 };
1657 struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1]; 1691 struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
1658 int error; 1692 int error;
diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h
index eb0b177300ad..90bbe3785504 100644
--- a/net/openvswitch/flow_netlink.h
+++ b/net/openvswitch/flow_netlink.h
@@ -37,6 +37,7 @@
37 37
38#include "flow.h" 38#include "flow.h"
39 39
40size_t ovs_tun_key_attr_size(void);
40size_t ovs_key_attr_size(void); 41size_t ovs_key_attr_size(void);
41 42
42void ovs_match_init(struct sw_flow_match *match, 43void ovs_match_init(struct sw_flow_match *match,
@@ -49,6 +50,8 @@ int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *);
49int ovs_nla_get_match(struct sw_flow_match *match, 50int ovs_nla_get_match(struct sw_flow_match *match,
50 const struct nlattr *, 51 const struct nlattr *,
51 const struct nlattr *); 52 const struct nlattr *);
53int ovs_nla_put_egress_tunnel_key(struct sk_buff *,
54 const struct ovs_tunnel_info *);
52 55
53int ovs_nla_copy_actions(const struct nlattr *attr, 56int ovs_nla_copy_actions(const struct nlattr *attr,
54 const struct sw_flow_key *key, 57 const struct sw_flow_key *key,
diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c
index 70c9765011f4..e31f19c922e2 100644
--- a/net/openvswitch/vport-geneve.c
+++ b/net/openvswitch/vport-geneve.c
@@ -97,7 +97,9 @@ static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb)
97 97
98 key = vni_to_tunnel_id(geneveh->vni); 98 key = vni_to_tunnel_id(geneveh->vni);
99 99
100 ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key, flags, 100 ovs_flow_tun_info_init(&tun_info, ip_hdr(skb),
101 udp_hdr(skb)->source, udp_hdr(skb)->dest,
102 key, flags,
101 geneveh->options, opts_len); 103 geneveh->options, opts_len);
102 104
103 ovs_vport_receive(vport, skb, &tun_info); 105 ovs_vport_receive(vport, skb, &tun_info);
@@ -228,6 +230,22 @@ static const char *geneve_get_name(const struct vport *vport)
228 return geneve_port->name; 230 return geneve_port->name;
229} 231}
230 232
233static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
234 struct ovs_tunnel_info *egress_tun_info)
235{
236 struct geneve_port *geneve_port = geneve_vport(vport);
237 struct net *net = ovs_dp_get_net(vport->dp);
238 __be16 dport = inet_sk(geneve_port->gs->sock->sk)->inet_sport;
239 __be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true);
240
241 /* Get tp_src and tp_dst, refert to geneve_build_header().
242 */
243 return ovs_tunnel_get_egress_info(egress_tun_info,
244 ovs_dp_get_net(vport->dp),
245 OVS_CB(skb)->egress_tun_info,
246 IPPROTO_UDP, skb->mark, sport, dport);
247}
248
231static struct vport_ops ovs_geneve_vport_ops = { 249static struct vport_ops ovs_geneve_vport_ops = {
232 .type = OVS_VPORT_TYPE_GENEVE, 250 .type = OVS_VPORT_TYPE_GENEVE,
233 .create = geneve_tnl_create, 251 .create = geneve_tnl_create,
@@ -236,6 +254,7 @@ static struct vport_ops ovs_geneve_vport_ops = {
236 .get_options = geneve_get_options, 254 .get_options = geneve_get_options,
237 .send = geneve_tnl_send, 255 .send = geneve_tnl_send,
238 .owner = THIS_MODULE, 256 .owner = THIS_MODULE,
257 .get_egress_tun_info = geneve_get_egress_tun_info,
239}; 258};
240 259
241static int __init ovs_geneve_tnl_init(void) 260static int __init ovs_geneve_tnl_init(void)
diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c
index 00270b608844..8e61a5c6ae7c 100644
--- a/net/openvswitch/vport-gre.c
+++ b/net/openvswitch/vport-gre.c
@@ -108,7 +108,7 @@ static int gre_rcv(struct sk_buff *skb,
108 return PACKET_REJECT; 108 return PACKET_REJECT;
109 109
110 key = key_to_tunnel_id(tpi->key, tpi->seq); 110 key = key_to_tunnel_id(tpi->key, tpi->seq);
111 ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), key, 111 ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), 0, 0, key,
112 filter_tnl_flags(tpi->flags), NULL, 0); 112 filter_tnl_flags(tpi->flags), NULL, 0);
113 113
114 ovs_vport_receive(vport, skb, &tun_info); 114 ovs_vport_receive(vport, skb, &tun_info);
@@ -284,12 +284,22 @@ static void gre_tnl_destroy(struct vport *vport)
284 gre_exit(); 284 gre_exit();
285} 285}
286 286
287static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
288 struct ovs_tunnel_info *egress_tun_info)
289{
290 return ovs_tunnel_get_egress_info(egress_tun_info,
291 ovs_dp_get_net(vport->dp),
292 OVS_CB(skb)->egress_tun_info,
293 IPPROTO_GRE, skb->mark, 0, 0);
294}
295
287static struct vport_ops ovs_gre_vport_ops = { 296static struct vport_ops ovs_gre_vport_ops = {
288 .type = OVS_VPORT_TYPE_GRE, 297 .type = OVS_VPORT_TYPE_GRE,
289 .create = gre_create, 298 .create = gre_create,
290 .destroy = gre_tnl_destroy, 299 .destroy = gre_tnl_destroy,
291 .get_name = gre_get_name, 300 .get_name = gre_get_name,
292 .send = gre_tnl_send, 301 .send = gre_tnl_send,
302 .get_egress_tun_info = gre_get_egress_tun_info,
293 .owner = THIS_MODULE, 303 .owner = THIS_MODULE,
294}; 304};
295 305
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c
index 965e7500c5a6..38f95a52241b 100644
--- a/net/openvswitch/vport-vxlan.c
+++ b/net/openvswitch/vport-vxlan.c
@@ -69,7 +69,9 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, __be32 vx_vni)
69 /* Save outer tunnel values */ 69 /* Save outer tunnel values */
70 iph = ip_hdr(skb); 70 iph = ip_hdr(skb);
71 key = cpu_to_be64(ntohl(vx_vni) >> 8); 71 key = cpu_to_be64(ntohl(vx_vni) >> 8);
72 ovs_flow_tun_info_init(&tun_info, iph, key, TUNNEL_KEY, NULL, 0); 72 ovs_flow_tun_info_init(&tun_info, iph,
73 udp_hdr(skb)->source, udp_hdr(skb)->dest,
74 key, TUNNEL_KEY, NULL, 0);
73 75
74 ovs_vport_receive(vport, skb, &tun_info); 76 ovs_vport_receive(vport, skb, &tun_info);
75} 77}
@@ -189,6 +191,25 @@ error:
189 return err; 191 return err;
190} 192}
191 193
194static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
195 struct ovs_tunnel_info *egress_tun_info)
196{
197 struct net *net = ovs_dp_get_net(vport->dp);
198 struct vxlan_port *vxlan_port = vxlan_vport(vport);
199 __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport;
200 __be16 src_port;
201 int port_min;
202 int port_max;
203
204 inet_get_local_port_range(net, &port_min, &port_max);
205 src_port = udp_flow_src_port(net, skb, 0, 0, true);
206
207 return ovs_tunnel_get_egress_info(egress_tun_info, net,
208 OVS_CB(skb)->egress_tun_info,
209 IPPROTO_UDP, skb->mark,
210 src_port, dst_port);
211}
212
192static const char *vxlan_get_name(const struct vport *vport) 213static const char *vxlan_get_name(const struct vport *vport)
193{ 214{
194 struct vxlan_port *vxlan_port = vxlan_vport(vport); 215 struct vxlan_port *vxlan_port = vxlan_vport(vport);
@@ -202,6 +223,7 @@ static struct vport_ops ovs_vxlan_vport_ops = {
202 .get_name = vxlan_get_name, 223 .get_name = vxlan_get_name,
203 .get_options = vxlan_get_options, 224 .get_options = vxlan_get_options,
204 .send = vxlan_tnl_send, 225 .send = vxlan_tnl_send,
226 .get_egress_tun_info = vxlan_get_egress_tun_info,
205 .owner = THIS_MODULE, 227 .owner = THIS_MODULE,
206}; 228};
207 229
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 4b5dd18953a6..630e81984b65 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -573,3 +573,64 @@ void ovs_vport_deferred_free(struct vport *vport)
573 call_rcu(&vport->rcu, free_vport_rcu); 573 call_rcu(&vport->rcu, free_vport_rcu);
574} 574}
575EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); 575EXPORT_SYMBOL_GPL(ovs_vport_deferred_free);
576
577int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info,
578 struct net *net,
579 const struct ovs_tunnel_info *tun_info,
580 u8 ipproto,
581 u32 skb_mark,
582 __be16 tp_src,
583 __be16 tp_dst)
584{
585 const struct ovs_key_ipv4_tunnel *tun_key;
586 struct rtable *rt;
587 struct flowi4 fl;
588
589 if (unlikely(!tun_info))
590 return -EINVAL;
591
592 tun_key = &tun_info->tunnel;
593
594 /* Route lookup to get srouce IP address.
595 * The process may need to be changed if the corresponding process
596 * in vports ops changed.
597 */
598 memset(&fl, 0, sizeof(fl));
599 fl.daddr = tun_key->ipv4_dst;
600 fl.saddr = tun_key->ipv4_src;
601 fl.flowi4_tos = RT_TOS(tun_key->ipv4_tos);
602 fl.flowi4_mark = skb_mark;
603 fl.flowi4_proto = IPPROTO_GRE;
604
605 rt = ip_route_output_key(net, &fl);
606 if (IS_ERR(rt))
607 return PTR_ERR(rt);
608
609 ip_rt_put(rt);
610
611 /* Generate egress_tun_info based on tun_info,
612 * saddr, tp_src and tp_dst
613 */
614 __ovs_flow_tun_info_init(egress_tun_info,
615 fl.saddr, tun_key->ipv4_dst,
616 tun_key->ipv4_tos,
617 tun_key->ipv4_ttl,
618 tp_src, tp_dst,
619 tun_key->tun_id,
620 tun_key->tun_flags,
621 tun_info->options,
622 tun_info->options_len);
623
624 return 0;
625}
626EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info);
627
628int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
629 struct ovs_tunnel_info *info)
630{
631 /* get_egress_tun_info() is only implemented on tunnel ports. */
632 if (unlikely(!vport->ops->get_egress_tun_info))
633 return -EINVAL;
634
635 return vport->ops->get_egress_tun_info(vport, skb, info);
636}
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index e41c3facf799..0635d1d761e9 100644
--- a/net/openvswitch/vport.h
+++ b/net/openvswitch/vport.h
@@ -58,6 +58,16 @@ u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *);
58 58
59int ovs_vport_send(struct vport *, struct sk_buff *); 59int ovs_vport_send(struct vport *, struct sk_buff *);
60 60
61int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info,
62 struct net *net,
63 const struct ovs_tunnel_info *tun_info,
64 u8 ipproto,
65 u32 skb_mark,
66 __be16 tp_src,
67 __be16 tp_dst);
68int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
69 struct ovs_tunnel_info *info);
70
61/* The following definitions are for implementers of vport devices: */ 71/* The following definitions are for implementers of vport devices: */
62 72
63struct vport_err_stats { 73struct vport_err_stats {
@@ -146,6 +156,8 @@ struct vport_parms {
146 * @get_name: Get the device's name. 156 * @get_name: Get the device's name.
147 * @send: Send a packet on the device. Returns the length of the packet sent, 157 * @send: Send a packet on the device. Returns the length of the packet sent,
148 * zero for dropped packets or negative for error. 158 * zero for dropped packets or negative for error.
159 * @get_egress_tun_info: Get the egress tunnel 5-tuple and other info for
160 * a packet.
149 */ 161 */
150struct vport_ops { 162struct vport_ops {
151 enum ovs_vport_type type; 163 enum ovs_vport_type type;
@@ -161,6 +173,8 @@ struct vport_ops {
161 const char *(*get_name)(const struct vport *); 173 const char *(*get_name)(const struct vport *);
162 174
163 int (*send)(struct vport *, struct sk_buff *); 175 int (*send)(struct vport *, struct sk_buff *);
176 int (*get_egress_tun_info)(struct vport *, struct sk_buff *,
177 struct ovs_tunnel_info *);
164 178
165 struct module *owner; 179 struct module *owner;
166 struct list_head list; 180 struct list_head list;