diff options
author | Jiri Benc <jbenc@redhat.com> | 2016-11-10 10:28:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-13 00:51:02 -0500 |
commit | e2d9d8358cb961340ef88620b6a25ba4557033d5 (patch) | |
tree | c2735d79cdbe2eb2919d41939d3f575648e50b30 /net/openvswitch | |
parent | 329f45bc4f191c663dc156c510816411a4310578 (diff) |
openvswitch: pass mac_proto to ovs_vport_send
We'll need it to alter packets sent to ARPHRD_NONE interfaces.
Change do_output() to use the actual L2 header size of the packet when
deciding on the minimum cutlen. The assumption here is that what matters is
not the output interface hard_header_len but rather the L2 header of the
particular packet. For example, ARPHRD_NONE tunnels that encapsulate
Ethernet should get at least the Ethernet header.
Signed-off-by: Jiri Benc <jbenc@redhat.com>
Acked-by: Pravin B Shelar <pshelar@ovn.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/actions.c | 29 | ||||
-rw-r--r-- | net/openvswitch/vport.c | 2 | ||||
-rw-r--r-- | net/openvswitch/vport.h | 2 |
3 files changed, 19 insertions, 14 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 44144f914920..dc8bb97e2258 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
@@ -66,6 +66,7 @@ struct ovs_frag_data { | |||
66 | u16 vlan_tci; | 66 | u16 vlan_tci; |
67 | __be16 vlan_proto; | 67 | __be16 vlan_proto; |
68 | unsigned int l2_len; | 68 | unsigned int l2_len; |
69 | u8 mac_proto; | ||
69 | u8 l2_data[MAX_L2_LEN]; | 70 | u8 l2_data[MAX_L2_LEN]; |
70 | }; | 71 | }; |
71 | 72 | ||
@@ -673,7 +674,7 @@ static int ovs_vport_output(struct net *net, struct sock *sk, struct sk_buff *sk | |||
673 | skb_reset_mac_len(skb); | 674 | skb_reset_mac_len(skb); |
674 | } | 675 | } |
675 | 676 | ||
676 | ovs_vport_send(vport, skb); | 677 | ovs_vport_send(vport, skb, data->mac_proto); |
677 | return 0; | 678 | return 0; |
678 | } | 679 | } |
679 | 680 | ||
@@ -692,7 +693,7 @@ static struct dst_ops ovs_dst_ops = { | |||
692 | * ovs_vport_output(), which is called once per fragmented packet. | 693 | * ovs_vport_output(), which is called once per fragmented packet. |
693 | */ | 694 | */ |
694 | static void prepare_frag(struct vport *vport, struct sk_buff *skb, | 695 | static void prepare_frag(struct vport *vport, struct sk_buff *skb, |
695 | u16 orig_network_offset) | 696 | u16 orig_network_offset, u8 mac_proto) |
696 | { | 697 | { |
697 | unsigned int hlen = skb_network_offset(skb); | 698 | unsigned int hlen = skb_network_offset(skb); |
698 | struct ovs_frag_data *data; | 699 | struct ovs_frag_data *data; |
@@ -705,6 +706,7 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb, | |||
705 | data->network_offset = orig_network_offset; | 706 | data->network_offset = orig_network_offset; |
706 | data->vlan_tci = skb->vlan_tci; | 707 | data->vlan_tci = skb->vlan_tci; |
707 | data->vlan_proto = skb->vlan_proto; | 708 | data->vlan_proto = skb->vlan_proto; |
709 | data->mac_proto = mac_proto; | ||
708 | data->l2_len = hlen; | 710 | data->l2_len = hlen; |
709 | memcpy(&data->l2_data, skb->data, hlen); | 711 | memcpy(&data->l2_data, skb->data, hlen); |
710 | 712 | ||
@@ -713,7 +715,8 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb, | |||
713 | } | 715 | } |
714 | 716 | ||
715 | static void ovs_fragment(struct net *net, struct vport *vport, | 717 | static void ovs_fragment(struct net *net, struct vport *vport, |
716 | struct sk_buff *skb, u16 mru, __be16 ethertype) | 718 | struct sk_buff *skb, u16 mru, |
719 | struct sw_flow_key *key) | ||
717 | { | 720 | { |
718 | u16 orig_network_offset = 0; | 721 | u16 orig_network_offset = 0; |
719 | 722 | ||
@@ -727,11 +730,12 @@ static void ovs_fragment(struct net *net, struct vport *vport, | |||
727 | goto err; | 730 | goto err; |
728 | } | 731 | } |
729 | 732 | ||
730 | if (ethertype == htons(ETH_P_IP)) { | 733 | if (key->eth.type == htons(ETH_P_IP)) { |
731 | struct dst_entry ovs_dst; | 734 | struct dst_entry ovs_dst; |
732 | unsigned long orig_dst; | 735 | unsigned long orig_dst; |
733 | 736 | ||
734 | prepare_frag(vport, skb, orig_network_offset); | 737 | prepare_frag(vport, skb, orig_network_offset, |
738 | ovs_key_mac_proto(key)); | ||
735 | dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1, | 739 | dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1, |
736 | DST_OBSOLETE_NONE, DST_NOCOUNT); | 740 | DST_OBSOLETE_NONE, DST_NOCOUNT); |
737 | ovs_dst.dev = vport->dev; | 741 | ovs_dst.dev = vport->dev; |
@@ -742,7 +746,7 @@ static void ovs_fragment(struct net *net, struct vport *vport, | |||
742 | 746 | ||
743 | ip_do_fragment(net, skb->sk, skb, ovs_vport_output); | 747 | ip_do_fragment(net, skb->sk, skb, ovs_vport_output); |
744 | refdst_drop(orig_dst); | 748 | refdst_drop(orig_dst); |
745 | } else if (ethertype == htons(ETH_P_IPV6)) { | 749 | } else if (key->eth.type == htons(ETH_P_IPV6)) { |
746 | const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops(); | 750 | const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops(); |
747 | unsigned long orig_dst; | 751 | unsigned long orig_dst; |
748 | struct rt6_info ovs_rt; | 752 | struct rt6_info ovs_rt; |
@@ -751,7 +755,8 @@ static void ovs_fragment(struct net *net, struct vport *vport, | |||
751 | goto err; | 755 | goto err; |
752 | } | 756 | } |
753 | 757 | ||
754 | prepare_frag(vport, skb, orig_network_offset); | 758 | prepare_frag(vport, skb, orig_network_offset, |
759 | ovs_key_mac_proto(key)); | ||
755 | memset(&ovs_rt, 0, sizeof(ovs_rt)); | 760 | memset(&ovs_rt, 0, sizeof(ovs_rt)); |
756 | dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1, | 761 | dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1, |
757 | DST_OBSOLETE_NONE, DST_NOCOUNT); | 762 | DST_OBSOLETE_NONE, DST_NOCOUNT); |
@@ -765,7 +770,7 @@ static void ovs_fragment(struct net *net, struct vport *vport, | |||
765 | refdst_drop(orig_dst); | 770 | refdst_drop(orig_dst); |
766 | } else { | 771 | } else { |
767 | WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.", | 772 | WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.", |
768 | ovs_vport_name(vport), ntohs(ethertype), mru, | 773 | ovs_vport_name(vport), ntohs(key->eth.type), mru, |
769 | vport->dev->mtu); | 774 | vport->dev->mtu); |
770 | goto err; | 775 | goto err; |
771 | } | 776 | } |
@@ -785,19 +790,19 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, | |||
785 | u32 cutlen = OVS_CB(skb)->cutlen; | 790 | u32 cutlen = OVS_CB(skb)->cutlen; |
786 | 791 | ||
787 | if (unlikely(cutlen > 0)) { | 792 | if (unlikely(cutlen > 0)) { |
788 | if (skb->len - cutlen > ETH_HLEN) | 793 | if (skb->len - cutlen > ovs_mac_header_len(key)) |
789 | pskb_trim(skb, skb->len - cutlen); | 794 | pskb_trim(skb, skb->len - cutlen); |
790 | else | 795 | else |
791 | pskb_trim(skb, ETH_HLEN); | 796 | pskb_trim(skb, ovs_mac_header_len(key)); |
792 | } | 797 | } |
793 | 798 | ||
794 | if (likely(!mru || | 799 | if (likely(!mru || |
795 | (skb->len <= mru + vport->dev->hard_header_len))) { | 800 | (skb->len <= mru + vport->dev->hard_header_len))) { |
796 | ovs_vport_send(vport, skb); | 801 | ovs_vport_send(vport, skb, ovs_key_mac_proto(key)); |
797 | } else if (mru <= vport->dev->mtu) { | 802 | } else if (mru <= vport->dev->mtu) { |
798 | struct net *net = read_pnet(&dp->net); | 803 | struct net *net = read_pnet(&dp->net); |
799 | 804 | ||
800 | ovs_fragment(net, vport, skb, mru, key->eth.type); | 805 | ovs_fragment(net, vport, skb, mru, key); |
801 | } else { | 806 | } else { |
802 | kfree_skb(skb); | 807 | kfree_skb(skb); |
803 | } | 808 | } |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 3e131f6868f2..898ed377b5cc 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
@@ -481,7 +481,7 @@ static unsigned int packet_length(const struct sk_buff *skb, | |||
481 | return length; | 481 | return length; |
482 | } | 482 | } |
483 | 483 | ||
484 | void ovs_vport_send(struct vport *vport, struct sk_buff *skb) | 484 | void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto) |
485 | { | 485 | { |
486 | int mtu = vport->dev->mtu; | 486 | int mtu = vport->dev->mtu; |
487 | 487 | ||
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 46e5b69927c7..cda66c26ad08 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h | |||
@@ -197,6 +197,6 @@ int __ovs_vport_ops_register(struct vport_ops *ops); | |||
197 | }) | 197 | }) |
198 | 198 | ||
199 | void ovs_vport_ops_unregister(struct vport_ops *ops); | 199 | void ovs_vport_ops_unregister(struct vport_ops *ops); |
200 | void ovs_vport_send(struct vport *vport, struct sk_buff *skb); | 200 | void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto); |
201 | 201 | ||
202 | #endif /* vport.h */ | 202 | #endif /* vport.h */ |