diff options
author | Jiri Benc <jbenc@redhat.com> | 2016-11-10 10:28:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-13 00:51:02 -0500 |
commit | 5108bbaddc37c1c8583f0cf2562d7d3463cd12cb (patch) | |
tree | 6f3b06a52f5ef5b64c66eefb94f51c76dad00d79 /net | |
parent | 1560a074df6297e76278e459ca3eb9ff83a6f878 (diff) |
openvswitch: add processing of L3 packets
Support receiving, extracting flow key and sending of L3 packets (packets
without an Ethernet header).
Note that even after this patch, non-Ethernet interfaces are still not
allowed to be added to bridges. Similarly, netlink interface for sending and
receiving L3 packets to/from user space is not in place yet.
Based on previous versions by Lorand Jakab and Simon Horman.
Signed-off-by: Lorand Jakab <lojakab@cisco.com>
Signed-off-by: Simon Horman <simon.horman@netronome.com>
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')
-rw-r--r-- | net/openvswitch/datapath.c | 13 | ||||
-rw-r--r-- | net/openvswitch/flow.c | 106 | ||||
-rw-r--r-- | net/openvswitch/vport.c | 19 |
3 files changed, 101 insertions, 37 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index fa8760176b7d..1402f1be642d 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -560,7 +560,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
560 | struct sw_flow *flow; | 560 | struct sw_flow *flow; |
561 | struct sw_flow_actions *sf_acts; | 561 | struct sw_flow_actions *sf_acts; |
562 | struct datapath *dp; | 562 | struct datapath *dp; |
563 | struct ethhdr *eth; | ||
564 | struct vport *input_vport; | 563 | struct vport *input_vport; |
565 | u16 mru = 0; | 564 | u16 mru = 0; |
566 | int len; | 565 | int len; |
@@ -581,17 +580,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
581 | 580 | ||
582 | nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len); | 581 | nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len); |
583 | 582 | ||
584 | skb_reset_mac_header(packet); | ||
585 | eth = eth_hdr(packet); | ||
586 | |||
587 | /* Normally, setting the skb 'protocol' field would be handled by a | ||
588 | * call to eth_type_trans(), but it assumes there's a sending | ||
589 | * device, which we may not have. */ | ||
590 | if (eth_proto_is_802_3(eth->h_proto)) | ||
591 | packet->protocol = eth->h_proto; | ||
592 | else | ||
593 | packet->protocol = htons(ETH_P_802_2); | ||
594 | |||
595 | /* Set packet's mru */ | 583 | /* Set packet's mru */ |
596 | if (a[OVS_PACKET_ATTR_MRU]) { | 584 | if (a[OVS_PACKET_ATTR_MRU]) { |
597 | mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]); | 585 | mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]); |
@@ -618,6 +606,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
618 | rcu_assign_pointer(flow->sf_acts, acts); | 606 | rcu_assign_pointer(flow->sf_acts, acts); |
619 | packet->priority = flow->key.phy.priority; | 607 | packet->priority = flow->key.phy.priority; |
620 | packet->mark = flow->key.phy.skb_mark; | 608 | packet->mark = flow->key.phy.skb_mark; |
609 | packet->protocol = flow->key.eth.type; | ||
621 | 610 | ||
622 | rcu_read_lock(); | 611 | rcu_read_lock(); |
623 | dp = get_dp_rcu(net, ovs_header->dp_ifindex); | 612 | dp = get_dp_rcu(net, ovs_header->dp_ifindex); |
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 96c8c4716603..08aa926cd5cf 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
@@ -334,14 +334,17 @@ static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh) | |||
334 | return 1; | 334 | return 1; |
335 | } | 335 | } |
336 | 336 | ||
337 | static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key) | 337 | static void clear_vlan(struct sw_flow_key *key) |
338 | { | 338 | { |
339 | int res; | ||
340 | |||
341 | key->eth.vlan.tci = 0; | 339 | key->eth.vlan.tci = 0; |
342 | key->eth.vlan.tpid = 0; | 340 | key->eth.vlan.tpid = 0; |
343 | key->eth.cvlan.tci = 0; | 341 | key->eth.cvlan.tci = 0; |
344 | key->eth.cvlan.tpid = 0; | 342 | key->eth.cvlan.tpid = 0; |
343 | } | ||
344 | |||
345 | static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key) | ||
346 | { | ||
347 | int res; | ||
345 | 348 | ||
346 | if (skb_vlan_tag_present(skb)) { | 349 | if (skb_vlan_tag_present(skb)) { |
347 | key->eth.vlan.tci = htons(skb->vlan_tci); | 350 | key->eth.vlan.tci = htons(skb->vlan_tci); |
@@ -483,17 +486,20 @@ invalid: | |||
483 | * | 486 | * |
484 | * Returns 0 if successful, otherwise a negative errno value. | 487 | * Returns 0 if successful, otherwise a negative errno value. |
485 | * | 488 | * |
486 | * Initializes @skb header pointers as follows: | 489 | * Initializes @skb header fields as follows: |
487 | * | 490 | * |
488 | * - skb->mac_header: the Ethernet header. | 491 | * - skb->mac_header: the L2 header. |
489 | * | 492 | * |
490 | * - skb->network_header: just past the Ethernet header, or just past the | 493 | * - skb->network_header: just past the L2 header, or just past the |
491 | * VLAN header, to the first byte of the Ethernet payload. | 494 | * VLAN header, to the first byte of the L2 payload. |
492 | * | 495 | * |
493 | * - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6 | 496 | * - skb->transport_header: If key->eth.type is ETH_P_IP or ETH_P_IPV6 |
494 | * on output, then just past the IP header, if one is present and | 497 | * on output, then just past the IP header, if one is present and |
495 | * of a correct length, otherwise the same as skb->network_header. | 498 | * of a correct length, otherwise the same as skb->network_header. |
496 | * For other key->eth.type values it is left untouched. | 499 | * For other key->eth.type values it is left untouched. |
500 | * | ||
501 | * - skb->protocol: the type of the data starting at skb->network_header. | ||
502 | * Equals to key->eth.type. | ||
497 | */ | 503 | */ |
498 | static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | 504 | static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) |
499 | { | 505 | { |
@@ -505,28 +511,35 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
505 | 511 | ||
506 | skb_reset_mac_header(skb); | 512 | skb_reset_mac_header(skb); |
507 | 513 | ||
508 | /* Link layer. We are guaranteed to have at least the 14 byte Ethernet | 514 | /* Link layer. */ |
509 | * header in the linear data area. | 515 | clear_vlan(key); |
510 | */ | 516 | if (key->mac_proto == MAC_PROTO_NONE) { |
511 | eth = eth_hdr(skb); | 517 | if (unlikely(eth_type_vlan(skb->protocol))) |
512 | ether_addr_copy(key->eth.src, eth->h_source); | 518 | return -EINVAL; |
513 | ether_addr_copy(key->eth.dst, eth->h_dest); | ||
514 | 519 | ||
515 | __skb_pull(skb, 2 * ETH_ALEN); | 520 | skb_reset_network_header(skb); |
516 | /* We are going to push all headers that we pull, so no need to | 521 | } else { |
517 | * update skb->csum here. | 522 | eth = eth_hdr(skb); |
518 | */ | 523 | ether_addr_copy(key->eth.src, eth->h_source); |
524 | ether_addr_copy(key->eth.dst, eth->h_dest); | ||
519 | 525 | ||
520 | if (unlikely(parse_vlan(skb, key))) | 526 | __skb_pull(skb, 2 * ETH_ALEN); |
521 | return -ENOMEM; | 527 | /* We are going to push all headers that we pull, so no need to |
528 | * update skb->csum here. | ||
529 | */ | ||
522 | 530 | ||
523 | key->eth.type = parse_ethertype(skb); | 531 | if (unlikely(parse_vlan(skb, key))) |
524 | if (unlikely(key->eth.type == htons(0))) | 532 | return -ENOMEM; |
525 | return -ENOMEM; | 533 | |
534 | skb->protocol = parse_ethertype(skb); | ||
535 | if (unlikely(skb->protocol == htons(0))) | ||
536 | return -ENOMEM; | ||
526 | 537 | ||
527 | skb_reset_network_header(skb); | 538 | skb_reset_network_header(skb); |
539 | __skb_push(skb, skb->data - skb_mac_header(skb)); | ||
540 | } | ||
528 | skb_reset_mac_len(skb); | 541 | skb_reset_mac_len(skb); |
529 | __skb_push(skb, skb->data - skb_mac_header(skb)); | 542 | key->eth.type = skb->protocol; |
530 | 543 | ||
531 | /* Network layer. */ | 544 | /* Network layer. */ |
532 | if (key->eth.type == htons(ETH_P_IP)) { | 545 | if (key->eth.type == htons(ETH_P_IP)) { |
@@ -721,9 +734,25 @@ int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) | |||
721 | return key_extract(skb, key); | 734 | return key_extract(skb, key); |
722 | } | 735 | } |
723 | 736 | ||
737 | static int key_extract_mac_proto(struct sk_buff *skb) | ||
738 | { | ||
739 | switch (skb->dev->type) { | ||
740 | case ARPHRD_ETHER: | ||
741 | return MAC_PROTO_ETHERNET; | ||
742 | case ARPHRD_NONE: | ||
743 | if (skb->protocol == htons(ETH_P_TEB)) | ||
744 | return MAC_PROTO_ETHERNET; | ||
745 | return MAC_PROTO_NONE; | ||
746 | } | ||
747 | WARN_ON_ONCE(1); | ||
748 | return -EINVAL; | ||
749 | } | ||
750 | |||
724 | int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, | 751 | int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, |
725 | struct sk_buff *skb, struct sw_flow_key *key) | 752 | struct sk_buff *skb, struct sw_flow_key *key) |
726 | { | 753 | { |
754 | int res; | ||
755 | |||
727 | /* Extract metadata from packet. */ | 756 | /* Extract metadata from packet. */ |
728 | if (tun_info) { | 757 | if (tun_info) { |
729 | key->tun_proto = ip_tunnel_info_af(tun_info); | 758 | key->tun_proto = ip_tunnel_info_af(tun_info); |
@@ -751,7 +780,10 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, | |||
751 | key->phy.skb_mark = skb->mark; | 780 | key->phy.skb_mark = skb->mark; |
752 | ovs_ct_fill_key(skb, key); | 781 | ovs_ct_fill_key(skb, key); |
753 | key->ovs_flow_hash = 0; | 782 | key->ovs_flow_hash = 0; |
754 | key->mac_proto = MAC_PROTO_ETHERNET; | 783 | res = key_extract_mac_proto(skb); |
784 | if (res < 0) | ||
785 | return res; | ||
786 | key->mac_proto = res; | ||
755 | key->recirc_id = 0; | 787 | key->recirc_id = 0; |
756 | 788 | ||
757 | return key_extract(skb, key); | 789 | return key_extract(skb, key); |
@@ -768,5 +800,29 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr, | |||
768 | if (err) | 800 | if (err) |
769 | return err; | 801 | return err; |
770 | 802 | ||
803 | if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) { | ||
804 | /* key_extract assumes that skb->protocol is set-up for | ||
805 | * layer 3 packets which is the case for other callers, | ||
806 | * in particular packets recieved from the network stack. | ||
807 | * Here the correct value can be set from the metadata | ||
808 | * extracted above. | ||
809 | */ | ||
810 | skb->protocol = key->eth.type; | ||
811 | } else { | ||
812 | struct ethhdr *eth; | ||
813 | |||
814 | skb_reset_mac_header(skb); | ||
815 | eth = eth_hdr(skb); | ||
816 | |||
817 | /* Normally, setting the skb 'protocol' field would be | ||
818 | * handled by a call to eth_type_trans(), but it assumes | ||
819 | * there's a sending device, which we may not have. | ||
820 | */ | ||
821 | if (eth_proto_is_802_3(eth->h_proto)) | ||
822 | skb->protocol = eth->h_proto; | ||
823 | else | ||
824 | skb->protocol = htons(ETH_P_802_2); | ||
825 | } | ||
826 | |||
771 | return key_extract(skb, key); | 827 | return key_extract(skb, key); |
772 | } | 828 | } |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 898ed377b5cc..b6c8524032a0 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
@@ -485,6 +485,25 @@ 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 | ||
488 | switch (vport->dev->type) { | ||
489 | case ARPHRD_NONE: | ||
490 | if (mac_proto == MAC_PROTO_ETHERNET) { | ||
491 | skb_reset_network_header(skb); | ||
492 | skb_reset_mac_len(skb); | ||
493 | skb->protocol = htons(ETH_P_TEB); | ||
494 | } else if (mac_proto != MAC_PROTO_NONE) { | ||
495 | WARN_ON_ONCE(1); | ||
496 | goto drop; | ||
497 | } | ||
498 | break; | ||
499 | case ARPHRD_ETHER: | ||
500 | if (mac_proto != MAC_PROTO_ETHERNET) | ||
501 | goto drop; | ||
502 | break; | ||
503 | default: | ||
504 | goto drop; | ||
505 | } | ||
506 | |||
488 | if (unlikely(packet_length(skb, vport->dev) > mtu && | 507 | if (unlikely(packet_length(skb, vport->dev) > mtu && |
489 | !skb_is_gso(skb))) { | 508 | !skb_is_gso(skb))) { |
490 | net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", | 509 | net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", |