diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/openvswitch/datapath.c | 21 | ||||
-rw-r--r-- | net/openvswitch/datapath.h | 5 | ||||
-rw-r--r-- | net/openvswitch/flow.c | 49 | ||||
-rw-r--r-- | net/openvswitch/flow.h | 6 | ||||
-rw-r--r-- | net/openvswitch/flow_netlink.c | 22 | ||||
-rw-r--r-- | net/openvswitch/flow_netlink.h | 4 | ||||
-rw-r--r-- | net/openvswitch/vport.c | 5 |
7 files changed, 71 insertions, 41 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 458096da138a..0cce8e60d5ed 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -237,8 +237,9 @@ void ovs_dp_detach_port(struct vport *p) | |||
237 | } | 237 | } |
238 | 238 | ||
239 | /* Must be called with rcu_read_lock. */ | 239 | /* Must be called with rcu_read_lock. */ |
240 | void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | 240 | void ovs_dp_process_received_packet(struct sk_buff *skb) |
241 | { | 241 | { |
242 | const struct vport *p = OVS_CB(skb)->input_vport; | ||
242 | struct datapath *dp = p->dp; | 243 | struct datapath *dp = p->dp; |
243 | struct sw_flow *flow; | 244 | struct sw_flow *flow; |
244 | struct dp_stats_percpu *stats; | 245 | struct dp_stats_percpu *stats; |
@@ -250,7 +251,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
250 | stats = this_cpu_ptr(dp->stats_percpu); | 251 | stats = this_cpu_ptr(dp->stats_percpu); |
251 | 252 | ||
252 | /* Extract flow from 'skb' into 'key'. */ | 253 | /* Extract flow from 'skb' into 'key'. */ |
253 | error = ovs_flow_extract(skb, p->port_no, &key); | 254 | error = ovs_flow_key_extract(skb, &key); |
254 | if (unlikely(error)) { | 255 | if (unlikely(error)) { |
255 | kfree_skb(skb); | 256 | kfree_skb(skb); |
256 | return; | 257 | return; |
@@ -514,6 +515,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
514 | struct sw_flow *flow; | 515 | struct sw_flow *flow; |
515 | struct datapath *dp; | 516 | struct datapath *dp; |
516 | struct ethhdr *eth; | 517 | struct ethhdr *eth; |
518 | struct vport *input_vport; | ||
517 | int len; | 519 | int len; |
518 | int err; | 520 | int err; |
519 | 521 | ||
@@ -548,13 +550,11 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
548 | if (IS_ERR(flow)) | 550 | if (IS_ERR(flow)) |
549 | goto err_kfree_skb; | 551 | goto err_kfree_skb; |
550 | 552 | ||
551 | err = ovs_flow_extract(packet, -1, &flow->key); | 553 | err = ovs_flow_key_extract_userspace(a[OVS_PACKET_ATTR_KEY], packet, |
554 | &flow->key); | ||
552 | if (err) | 555 | if (err) |
553 | goto err_flow_free; | 556 | goto err_flow_free; |
554 | 557 | ||
555 | err = ovs_nla_get_flow_metadata(flow, a[OVS_PACKET_ATTR_KEY]); | ||
556 | if (err) | ||
557 | goto err_flow_free; | ||
558 | acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); | 558 | acts = ovs_nla_alloc_flow_actions(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); |
559 | err = PTR_ERR(acts); | 559 | err = PTR_ERR(acts); |
560 | if (IS_ERR(acts)) | 560 | if (IS_ERR(acts)) |
@@ -576,6 +576,15 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
576 | if (!dp) | 576 | if (!dp) |
577 | goto err_unlock; | 577 | goto err_unlock; |
578 | 578 | ||
579 | input_vport = ovs_vport_rcu(dp, flow->key.phy.in_port); | ||
580 | if (!input_vport) | ||
581 | input_vport = ovs_vport_rcu(dp, OVSP_LOCAL); | ||
582 | |||
583 | if (!input_vport) | ||
584 | goto err_unlock; | ||
585 | |||
586 | OVS_CB(packet)->input_vport = input_vport; | ||
587 | |||
579 | local_bh_disable(); | 588 | local_bh_disable(); |
580 | err = ovs_execute_actions(dp, packet, &flow->key); | 589 | err = ovs_execute_actions(dp, packet, &flow->key); |
581 | local_bh_enable(); | 590 | local_bh_enable(); |
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index b576483aab7c..2b982fae6a11 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
@@ -97,10 +97,13 @@ struct datapath { | |||
97 | * @flow: The flow associated with this packet. May be %NULL if no flow. | 97 | * @flow: The flow associated with this packet. May be %NULL if no flow. |
98 | * @tun_key: Key for the tunnel that encapsulated this packet. NULL if the | 98 | * @tun_key: Key for the tunnel that encapsulated this packet. NULL if the |
99 | * packet is not being tunneled. | 99 | * packet is not being tunneled. |
100 | * @input_vport: The original vport packet came in on. This value is cached | ||
101 | * when a packet is received by OVS. | ||
100 | */ | 102 | */ |
101 | struct ovs_skb_cb { | 103 | struct ovs_skb_cb { |
102 | struct sw_flow *flow; | 104 | struct sw_flow *flow; |
103 | struct ovs_key_ipv4_tunnel *tun_key; | 105 | struct ovs_key_ipv4_tunnel *tun_key; |
106 | struct vport *input_vport; | ||
104 | }; | 107 | }; |
105 | #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) | 108 | #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) |
106 | 109 | ||
@@ -181,7 +184,7 @@ static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_n | |||
181 | extern struct notifier_block ovs_dp_device_notifier; | 184 | extern struct notifier_block ovs_dp_device_notifier; |
182 | extern struct genl_family dp_vport_genl_family; | 185 | extern struct genl_family dp_vport_genl_family; |
183 | 186 | ||
184 | void ovs_dp_process_received_packet(struct vport *, struct sk_buff *); | 187 | void ovs_dp_process_received_packet(struct sk_buff *); |
185 | void ovs_dp_detach_port(struct vport *); | 188 | void ovs_dp_detach_port(struct vport *); |
186 | int ovs_dp_upcall(struct datapath *, struct sk_buff *, | 189 | int ovs_dp_upcall(struct datapath *, struct sk_buff *, |
187 | const struct dp_upcall_info *); | 190 | const struct dp_upcall_info *); |
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 7064da92f420..d186eb65a391 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
@@ -16,8 +16,6 @@ | |||
16 | * 02110-1301, USA | 16 | * 02110-1301, USA |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include "flow.h" | ||
20 | #include "datapath.h" | ||
21 | #include <linux/uaccess.h> | 19 | #include <linux/uaccess.h> |
22 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
23 | #include <linux/etherdevice.h> | 21 | #include <linux/etherdevice.h> |
@@ -46,6 +44,10 @@ | |||
46 | #include <net/ipv6.h> | 44 | #include <net/ipv6.h> |
47 | #include <net/ndisc.h> | 45 | #include <net/ndisc.h> |
48 | 46 | ||
47 | #include "datapath.h" | ||
48 | #include "flow.h" | ||
49 | #include "flow_netlink.h" | ||
50 | |||
49 | u64 ovs_flow_used_time(unsigned long flow_jiffies) | 51 | u64 ovs_flow_used_time(unsigned long flow_jiffies) |
50 | { | 52 | { |
51 | struct timespec cur_ts; | 53 | struct timespec cur_ts; |
@@ -420,10 +422,9 @@ invalid: | |||
420 | } | 422 | } |
421 | 423 | ||
422 | /** | 424 | /** |
423 | * ovs_flow_extract - extracts a flow key from an Ethernet frame. | 425 | * key_extract - extracts a flow key from an Ethernet frame. |
424 | * @skb: sk_buff that contains the frame, with skb->data pointing to the | 426 | * @skb: sk_buff that contains the frame, with skb->data pointing to the |
425 | * Ethernet header | 427 | * Ethernet header |
426 | * @in_port: port number on which @skb was received. | ||
427 | * @key: output flow key | 428 | * @key: output flow key |
428 | * | 429 | * |
429 | * The caller must ensure that skb->len >= ETH_HLEN. | 430 | * The caller must ensure that skb->len >= ETH_HLEN. |
@@ -442,19 +443,11 @@ invalid: | |||
442 | * of a correct length, otherwise the same as skb->network_header. | 443 | * of a correct length, otherwise the same as skb->network_header. |
443 | * For other key->eth.type values it is left untouched. | 444 | * For other key->eth.type values it is left untouched. |
444 | */ | 445 | */ |
445 | int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key) | 446 | static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) |
446 | { | 447 | { |
447 | int error; | 448 | int error; |
448 | struct ethhdr *eth; | 449 | struct ethhdr *eth; |
449 | 450 | ||
450 | memset(key, 0, sizeof(*key)); | ||
451 | |||
452 | key->phy.priority = skb->priority; | ||
453 | if (OVS_CB(skb)->tun_key) | ||
454 | memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key)); | ||
455 | key->phy.in_port = in_port; | ||
456 | key->phy.skb_mark = skb->mark; | ||
457 | |||
458 | skb_reset_mac_header(skb); | 451 | skb_reset_mac_header(skb); |
459 | 452 | ||
460 | /* Link layer. We are guaranteed to have at least the 14 byte Ethernet | 453 | /* Link layer. We are guaranteed to have at least the 14 byte Ethernet |
@@ -610,6 +603,34 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key) | |||
610 | } | 603 | } |
611 | } | 604 | } |
612 | } | 605 | } |
613 | |||
614 | return 0; | 606 | return 0; |
615 | } | 607 | } |
608 | |||
609 | int ovs_flow_key_extract(struct sk_buff *skb, struct sw_flow_key *key) | ||
610 | { | ||
611 | /* Extract metadata from packet. */ | ||
612 | memset(key, 0, sizeof(*key)); | ||
613 | if (OVS_CB(skb)->tun_key) | ||
614 | memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key)); | ||
615 | |||
616 | key->phy.priority = skb->priority; | ||
617 | key->phy.in_port = OVS_CB(skb)->input_vport->port_no; | ||
618 | key->phy.skb_mark = skb->mark; | ||
619 | |||
620 | return key_extract(skb, key); | ||
621 | } | ||
622 | |||
623 | int ovs_flow_key_extract_userspace(const struct nlattr *attr, | ||
624 | struct sk_buff *skb, | ||
625 | struct sw_flow_key *key) | ||
626 | { | ||
627 | int err; | ||
628 | |||
629 | memset(key, 0, sizeof(*key)); | ||
630 | /* Extract metadata from netlink attributes. */ | ||
631 | err = ovs_nla_get_flow_metadata(attr, key); | ||
632 | if (err) | ||
633 | return err; | ||
634 | |||
635 | return key_extract(skb, key); | ||
636 | } | ||
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 5e5aaed3a85b..251789b6ec45 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h | |||
@@ -187,6 +187,10 @@ void ovs_flow_stats_get(const struct sw_flow *, struct ovs_flow_stats *, | |||
187 | void ovs_flow_stats_clear(struct sw_flow *); | 187 | void ovs_flow_stats_clear(struct sw_flow *); |
188 | u64 ovs_flow_used_time(unsigned long flow_jiffies); | 188 | u64 ovs_flow_used_time(unsigned long flow_jiffies); |
189 | 189 | ||
190 | int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *); | 190 | int ovs_flow_key_extract(struct sk_buff *skb, struct sw_flow_key *key); |
191 | /* Extract key from packet coming from userspace. */ | ||
192 | int ovs_flow_key_extract_userspace(const struct nlattr *attr, | ||
193 | struct sk_buff *skb, | ||
194 | struct sw_flow_key *key); | ||
191 | 195 | ||
192 | #endif /* flow.h */ | 196 | #endif /* flow.h */ |
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index d757848da89c..630b320fbf3e 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
@@ -836,7 +836,7 @@ int ovs_nla_get_match(struct sw_flow_match *match, | |||
836 | 836 | ||
837 | /** | 837 | /** |
838 | * ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key. | 838 | * ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key. |
839 | * @flow: Receives extracted in_port, priority, tun_key and skb_mark. | 839 | * @key: Receives extracted in_port, priority, tun_key and skb_mark. |
840 | * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute | 840 | * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute |
841 | * sequence. | 841 | * sequence. |
842 | * | 842 | * |
@@ -846,32 +846,24 @@ int ovs_nla_get_match(struct sw_flow_match *match, | |||
846 | * extracted from the packet itself. | 846 | * extracted from the packet itself. |
847 | */ | 847 | */ |
848 | 848 | ||
849 | int ovs_nla_get_flow_metadata(struct sw_flow *flow, | 849 | int ovs_nla_get_flow_metadata(const struct nlattr *attr, |
850 | const struct nlattr *attr) | 850 | struct sw_flow_key *key) |
851 | { | 851 | { |
852 | struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key; | ||
853 | const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; | 852 | const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; |
853 | struct sw_flow_match match; | ||
854 | u64 attrs = 0; | 854 | u64 attrs = 0; |
855 | int err; | 855 | int err; |
856 | struct sw_flow_match match; | ||
857 | |||
858 | flow->key.phy.in_port = DP_MAX_PORTS; | ||
859 | flow->key.phy.priority = 0; | ||
860 | flow->key.phy.skb_mark = 0; | ||
861 | memset(tun_key, 0, sizeof(flow->key.tun_key)); | ||
862 | 856 | ||
863 | err = parse_flow_nlattrs(attr, a, &attrs); | 857 | err = parse_flow_nlattrs(attr, a, &attrs); |
864 | if (err) | 858 | if (err) |
865 | return -EINVAL; | 859 | return -EINVAL; |
866 | 860 | ||
867 | memset(&match, 0, sizeof(match)); | 861 | memset(&match, 0, sizeof(match)); |
868 | match.key = &flow->key; | 862 | match.key = key; |
869 | 863 | ||
870 | err = metadata_from_nlattrs(&match, &attrs, a, false); | 864 | key->phy.in_port = DP_MAX_PORTS; |
871 | if (err) | ||
872 | return err; | ||
873 | 865 | ||
874 | return 0; | 866 | return metadata_from_nlattrs(&match, &attrs, a, false); |
875 | } | 867 | } |
876 | 868 | ||
877 | int ovs_nla_put_flow(const struct sw_flow_key *swkey, | 869 | int ovs_nla_put_flow(const struct sw_flow_key *swkey, |
diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h index 440151045d39..206e45add888 100644 --- a/net/openvswitch/flow_netlink.h +++ b/net/openvswitch/flow_netlink.h | |||
@@ -42,8 +42,8 @@ void ovs_match_init(struct sw_flow_match *match, | |||
42 | 42 | ||
43 | int ovs_nla_put_flow(const struct sw_flow_key *, | 43 | int ovs_nla_put_flow(const struct sw_flow_key *, |
44 | const struct sw_flow_key *, struct sk_buff *); | 44 | const struct sw_flow_key *, struct sk_buff *); |
45 | int ovs_nla_get_flow_metadata(struct sw_flow *flow, | 45 | int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *); |
46 | const struct nlattr *attr); | 46 | |
47 | int ovs_nla_get_match(struct sw_flow_match *match, | 47 | int ovs_nla_get_match(struct sw_flow_match *match, |
48 | const struct nlattr *, | 48 | const struct nlattr *, |
49 | const struct nlattr *); | 49 | const struct nlattr *); |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index f7e63f9df7b9..acf31aa89e01 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2007-2012 Nicira, Inc. | 2 | * Copyright (c) 2007-2014 Nicira, Inc. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of version 2 of the GNU General Public | 5 | * modify it under the terms of version 2 of the GNU General Public |
@@ -443,7 +443,8 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, | |||
443 | u64_stats_update_end(&stats->syncp); | 443 | u64_stats_update_end(&stats->syncp); |
444 | 444 | ||
445 | OVS_CB(skb)->tun_key = tun_key; | 445 | OVS_CB(skb)->tun_key = tun_key; |
446 | ovs_dp_process_received_packet(vport, skb); | 446 | OVS_CB(skb)->input_vport = vport; |
447 | ovs_dp_process_received_packet(skb); | ||
447 | } | 448 | } |
448 | 449 | ||
449 | /** | 450 | /** |