mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
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>
This commit is contained in:
parent
329f45bc4f
commit
e2d9d8358c
@ -66,6 +66,7 @@ struct ovs_frag_data {
|
|||||||
u16 vlan_tci;
|
u16 vlan_tci;
|
||||||
__be16 vlan_proto;
|
__be16 vlan_proto;
|
||||||
unsigned int l2_len;
|
unsigned int l2_len;
|
||||||
|
u8 mac_proto;
|
||||||
u8 l2_data[MAX_L2_LEN];
|
u8 l2_data[MAX_L2_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -673,7 +674,7 @@ static int ovs_vport_output(struct net *net, struct sock *sk, struct sk_buff *sk
|
|||||||
skb_reset_mac_len(skb);
|
skb_reset_mac_len(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
ovs_vport_send(vport, skb);
|
ovs_vport_send(vport, skb, data->mac_proto);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,7 +693,7 @@ static struct dst_ops ovs_dst_ops = {
|
|||||||
* ovs_vport_output(), which is called once per fragmented packet.
|
* ovs_vport_output(), which is called once per fragmented packet.
|
||||||
*/
|
*/
|
||||||
static void prepare_frag(struct vport *vport, struct sk_buff *skb,
|
static void prepare_frag(struct vport *vport, struct sk_buff *skb,
|
||||||
u16 orig_network_offset)
|
u16 orig_network_offset, u8 mac_proto)
|
||||||
{
|
{
|
||||||
unsigned int hlen = skb_network_offset(skb);
|
unsigned int hlen = skb_network_offset(skb);
|
||||||
struct ovs_frag_data *data;
|
struct ovs_frag_data *data;
|
||||||
@ -705,6 +706,7 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb,
|
|||||||
data->network_offset = orig_network_offset;
|
data->network_offset = orig_network_offset;
|
||||||
data->vlan_tci = skb->vlan_tci;
|
data->vlan_tci = skb->vlan_tci;
|
||||||
data->vlan_proto = skb->vlan_proto;
|
data->vlan_proto = skb->vlan_proto;
|
||||||
|
data->mac_proto = mac_proto;
|
||||||
data->l2_len = hlen;
|
data->l2_len = hlen;
|
||||||
memcpy(&data->l2_data, skb->data, hlen);
|
memcpy(&data->l2_data, skb->data, hlen);
|
||||||
|
|
||||||
@ -713,7 +715,8 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ovs_fragment(struct net *net, struct vport *vport,
|
static void ovs_fragment(struct net *net, struct vport *vport,
|
||||||
struct sk_buff *skb, u16 mru, __be16 ethertype)
|
struct sk_buff *skb, u16 mru,
|
||||||
|
struct sw_flow_key *key)
|
||||||
{
|
{
|
||||||
u16 orig_network_offset = 0;
|
u16 orig_network_offset = 0;
|
||||||
|
|
||||||
@ -727,11 +730,12 @@ static void ovs_fragment(struct net *net, struct vport *vport,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ethertype == htons(ETH_P_IP)) {
|
if (key->eth.type == htons(ETH_P_IP)) {
|
||||||
struct dst_entry ovs_dst;
|
struct dst_entry ovs_dst;
|
||||||
unsigned long orig_dst;
|
unsigned long orig_dst;
|
||||||
|
|
||||||
prepare_frag(vport, skb, orig_network_offset);
|
prepare_frag(vport, skb, orig_network_offset,
|
||||||
|
ovs_key_mac_proto(key));
|
||||||
dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1,
|
dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1,
|
||||||
DST_OBSOLETE_NONE, DST_NOCOUNT);
|
DST_OBSOLETE_NONE, DST_NOCOUNT);
|
||||||
ovs_dst.dev = vport->dev;
|
ovs_dst.dev = vport->dev;
|
||||||
@ -742,7 +746,7 @@ static void ovs_fragment(struct net *net, struct vport *vport,
|
|||||||
|
|
||||||
ip_do_fragment(net, skb->sk, skb, ovs_vport_output);
|
ip_do_fragment(net, skb->sk, skb, ovs_vport_output);
|
||||||
refdst_drop(orig_dst);
|
refdst_drop(orig_dst);
|
||||||
} else if (ethertype == htons(ETH_P_IPV6)) {
|
} else if (key->eth.type == htons(ETH_P_IPV6)) {
|
||||||
const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
|
const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
|
||||||
unsigned long orig_dst;
|
unsigned long orig_dst;
|
||||||
struct rt6_info ovs_rt;
|
struct rt6_info ovs_rt;
|
||||||
@ -751,7 +755,8 @@ static void ovs_fragment(struct net *net, struct vport *vport,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_frag(vport, skb, orig_network_offset);
|
prepare_frag(vport, skb, orig_network_offset,
|
||||||
|
ovs_key_mac_proto(key));
|
||||||
memset(&ovs_rt, 0, sizeof(ovs_rt));
|
memset(&ovs_rt, 0, sizeof(ovs_rt));
|
||||||
dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1,
|
dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1,
|
||||||
DST_OBSOLETE_NONE, DST_NOCOUNT);
|
DST_OBSOLETE_NONE, DST_NOCOUNT);
|
||||||
@ -765,7 +770,7 @@ static void ovs_fragment(struct net *net, struct vport *vport,
|
|||||||
refdst_drop(orig_dst);
|
refdst_drop(orig_dst);
|
||||||
} else {
|
} else {
|
||||||
WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
|
WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
|
||||||
ovs_vport_name(vport), ntohs(ethertype), mru,
|
ovs_vport_name(vport), ntohs(key->eth.type), mru,
|
||||||
vport->dev->mtu);
|
vport->dev->mtu);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -785,19 +790,19 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
|
|||||||
u32 cutlen = OVS_CB(skb)->cutlen;
|
u32 cutlen = OVS_CB(skb)->cutlen;
|
||||||
|
|
||||||
if (unlikely(cutlen > 0)) {
|
if (unlikely(cutlen > 0)) {
|
||||||
if (skb->len - cutlen > ETH_HLEN)
|
if (skb->len - cutlen > ovs_mac_header_len(key))
|
||||||
pskb_trim(skb, skb->len - cutlen);
|
pskb_trim(skb, skb->len - cutlen);
|
||||||
else
|
else
|
||||||
pskb_trim(skb, ETH_HLEN);
|
pskb_trim(skb, ovs_mac_header_len(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(!mru ||
|
if (likely(!mru ||
|
||||||
(skb->len <= mru + vport->dev->hard_header_len))) {
|
(skb->len <= mru + vport->dev->hard_header_len))) {
|
||||||
ovs_vport_send(vport, skb);
|
ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
|
||||||
} else if (mru <= vport->dev->mtu) {
|
} else if (mru <= vport->dev->mtu) {
|
||||||
struct net *net = read_pnet(&dp->net);
|
struct net *net = read_pnet(&dp->net);
|
||||||
|
|
||||||
ovs_fragment(net, vport, skb, mru, key->eth.type);
|
ovs_fragment(net, vport, skb, mru, key);
|
||||||
} else {
|
} else {
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
}
|
}
|
||||||
|
@ -481,7 +481,7 @@ static unsigned int packet_length(const struct sk_buff *skb,
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ovs_vport_send(struct vport *vport, struct sk_buff *skb)
|
void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto)
|
||||||
{
|
{
|
||||||
int mtu = vport->dev->mtu;
|
int mtu = vport->dev->mtu;
|
||||||
|
|
||||||
|
@ -197,6 +197,6 @@ int __ovs_vport_ops_register(struct vport_ops *ops);
|
|||||||
})
|
})
|
||||||
|
|
||||||
void ovs_vport_ops_unregister(struct vport_ops *ops);
|
void ovs_vport_ops_unregister(struct vport_ops *ops);
|
||||||
void ovs_vport_send(struct vport *vport, struct sk_buff *skb);
|
void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto);
|
||||||
|
|
||||||
#endif /* vport.h */
|
#endif /* vport.h */
|
||||||
|
Loading…
Reference in New Issue
Block a user