diff options
author | Jiri Benc <jbenc@redhat.com> | 2015-10-05 07:09:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-10-07 07:18:00 -0400 |
commit | 6b26ba3a7d952e611dcde1f3f77ce63bcc70540a (patch) | |
tree | 6c15c6b572dd2656ddd6401549b1cfbb4ecf1931 /net/openvswitch | |
parent | 00a93babd06aaad31d23384cda576ede0f586a8c (diff) |
openvswitch: netlink attributes for IPv6 tunneling
Add netlink attributes for IPv6 tunnel addresses. This enables IPv6 support
for tunnels.
Signed-off-by: Jiri Benc <jbenc@redhat.com>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/flow_netlink.c | 121 |
1 files changed, 84 insertions, 37 deletions
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 6be701f6b31b..77850f177a47 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
@@ -262,8 +262,8 @@ size_t ovs_tun_key_attr_size(void) | |||
262 | * updating this function. | 262 | * updating this function. |
263 | */ | 263 | */ |
264 | return nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */ | 264 | return nla_total_size(8) /* OVS_TUNNEL_KEY_ATTR_ID */ |
265 | + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */ | 265 | + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_SRC */ |
266 | + nla_total_size(4) /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */ | 266 | + nla_total_size(16) /* OVS_TUNNEL_KEY_ATTR_IPV[46]_DST */ |
267 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */ | 267 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TOS */ |
268 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */ | 268 | + nla_total_size(1) /* OVS_TUNNEL_KEY_ATTR_TTL */ |
269 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */ | 269 | + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */ |
@@ -323,6 +323,8 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] | |||
323 | [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE }, | 323 | [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE }, |
324 | [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED, | 324 | [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED, |
325 | .next = ovs_vxlan_ext_key_lens }, | 325 | .next = ovs_vxlan_ext_key_lens }, |
326 | [OVS_TUNNEL_KEY_ATTR_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, | ||
327 | [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = sizeof(struct in6_addr) }, | ||
326 | }; | 328 | }; |
327 | 329 | ||
328 | /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ | 330 | /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ |
@@ -542,14 +544,14 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr, | |||
542 | return 0; | 544 | return 0; |
543 | } | 545 | } |
544 | 546 | ||
545 | static int ipv4_tun_from_nlattr(const struct nlattr *attr, | 547 | static int ip_tun_from_nlattr(const struct nlattr *attr, |
546 | struct sw_flow_match *match, bool is_mask, | 548 | struct sw_flow_match *match, bool is_mask, |
547 | bool log) | 549 | bool log) |
548 | { | 550 | { |
549 | struct nlattr *a; | 551 | struct nlattr *a; |
550 | int rem; | 552 | int rem; |
551 | bool ttl = false; | 553 | bool ttl = false; |
552 | __be16 tun_flags = 0; | 554 | __be16 tun_flags = 0, ipv4 = false, ipv6 = false; |
553 | int opts_type = 0; | 555 | int opts_type = 0; |
554 | 556 | ||
555 | nla_for_each_nested(a, attr, rem) { | 557 | nla_for_each_nested(a, attr, rem) { |
@@ -578,10 +580,22 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
578 | case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: | 580 | case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: |
579 | SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src, | 581 | SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.src, |
580 | nla_get_in_addr(a), is_mask); | 582 | nla_get_in_addr(a), is_mask); |
583 | ipv4 = true; | ||
581 | break; | 584 | break; |
582 | case OVS_TUNNEL_KEY_ATTR_IPV4_DST: | 585 | case OVS_TUNNEL_KEY_ATTR_IPV4_DST: |
583 | SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst, | 586 | SW_FLOW_KEY_PUT(match, tun_key.u.ipv4.dst, |
584 | nla_get_in_addr(a), is_mask); | 587 | nla_get_in_addr(a), is_mask); |
588 | ipv4 = true; | ||
589 | break; | ||
590 | case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: | ||
591 | SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst, | ||
592 | nla_get_in6_addr(a), is_mask); | ||
593 | ipv6 = true; | ||
594 | break; | ||
595 | case OVS_TUNNEL_KEY_ATTR_IPV6_DST: | ||
596 | SW_FLOW_KEY_PUT(match, tun_key.u.ipv6.dst, | ||
597 | nla_get_in6_addr(a), is_mask); | ||
598 | ipv6 = true; | ||
585 | break; | 599 | break; |
586 | case OVS_TUNNEL_KEY_ATTR_TOS: | 600 | case OVS_TUNNEL_KEY_ATTR_TOS: |
587 | SW_FLOW_KEY_PUT(match, tun_key.tos, | 601 | SW_FLOW_KEY_PUT(match, tun_key.tos, |
@@ -636,7 +650,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
636 | opts_type = type; | 650 | opts_type = type; |
637 | break; | 651 | break; |
638 | default: | 652 | default: |
639 | OVS_NLERR(log, "Unknown IPv4 tunnel attribute %d", | 653 | OVS_NLERR(log, "Unknown IP tunnel attribute %d", |
640 | type); | 654 | type); |
641 | return -EINVAL; | 655 | return -EINVAL; |
642 | } | 656 | } |
@@ -646,22 +660,36 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
646 | if (is_mask) | 660 | if (is_mask) |
647 | SW_FLOW_KEY_MEMSET_FIELD(match, tun_proto, 0xff, true); | 661 | SW_FLOW_KEY_MEMSET_FIELD(match, tun_proto, 0xff, true); |
648 | else | 662 | else |
649 | SW_FLOW_KEY_PUT(match, tun_proto, AF_INET, false); | 663 | SW_FLOW_KEY_PUT(match, tun_proto, ipv6 ? AF_INET6 : AF_INET, |
664 | false); | ||
650 | 665 | ||
651 | if (rem > 0) { | 666 | if (rem > 0) { |
652 | OVS_NLERR(log, "IPv4 tunnel attribute has %d unknown bytes.", | 667 | OVS_NLERR(log, "IP tunnel attribute has %d unknown bytes.", |
653 | rem); | 668 | rem); |
654 | return -EINVAL; | 669 | return -EINVAL; |
655 | } | 670 | } |
656 | 671 | ||
672 | if (ipv4 && ipv6) { | ||
673 | OVS_NLERR(log, "Mixed IPv4 and IPv6 tunnel attributes"); | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | |||
657 | if (!is_mask) { | 677 | if (!is_mask) { |
658 | if (!match->key->tun_key.u.ipv4.dst) { | 678 | if (!ipv4 && !ipv6) { |
679 | OVS_NLERR(log, "IP tunnel dst address not specified"); | ||
680 | return -EINVAL; | ||
681 | } | ||
682 | if (ipv4 && !match->key->tun_key.u.ipv4.dst) { | ||
659 | OVS_NLERR(log, "IPv4 tunnel dst address is zero"); | 683 | OVS_NLERR(log, "IPv4 tunnel dst address is zero"); |
660 | return -EINVAL; | 684 | return -EINVAL; |
661 | } | 685 | } |
686 | if (ipv6 && ipv6_addr_any(&match->key->tun_key.u.ipv6.dst)) { | ||
687 | OVS_NLERR(log, "IPv6 tunnel dst address is zero"); | ||
688 | return -EINVAL; | ||
689 | } | ||
662 | 690 | ||
663 | if (!ttl) { | 691 | if (!ttl) { |
664 | OVS_NLERR(log, "IPv4 tunnel TTL not specified."); | 692 | OVS_NLERR(log, "IP tunnel TTL not specified."); |
665 | return -EINVAL; | 693 | return -EINVAL; |
666 | } | 694 | } |
667 | } | 695 | } |
@@ -686,21 +714,36 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb, | |||
686 | return 0; | 714 | return 0; |
687 | } | 715 | } |
688 | 716 | ||
689 | static int __ipv4_tun_to_nlattr(struct sk_buff *skb, | 717 | static int __ip_tun_to_nlattr(struct sk_buff *skb, |
690 | const struct ip_tunnel_key *output, | 718 | const struct ip_tunnel_key *output, |
691 | const void *tun_opts, int swkey_tun_opts_len) | 719 | const void *tun_opts, int swkey_tun_opts_len, |
720 | unsigned short tun_proto) | ||
692 | { | 721 | { |
693 | if (output->tun_flags & TUNNEL_KEY && | 722 | if (output->tun_flags & TUNNEL_KEY && |
694 | nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id)) | 723 | nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id)) |
695 | return -EMSGSIZE; | 724 | return -EMSGSIZE; |
696 | if (output->u.ipv4.src && | 725 | switch (tun_proto) { |
697 | nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, | 726 | case AF_INET: |
698 | output->u.ipv4.src)) | 727 | if (output->u.ipv4.src && |
699 | return -EMSGSIZE; | 728 | nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, |
700 | if (output->u.ipv4.dst && | 729 | output->u.ipv4.src)) |
701 | nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, | 730 | return -EMSGSIZE; |
702 | output->u.ipv4.dst)) | 731 | if (output->u.ipv4.dst && |
703 | return -EMSGSIZE; | 732 | nla_put_in_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, |
733 | output->u.ipv4.dst)) | ||
734 | return -EMSGSIZE; | ||
735 | break; | ||
736 | case AF_INET6: | ||
737 | if (!ipv6_addr_any(&output->u.ipv6.src) && | ||
738 | nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_SRC, | ||
739 | &output->u.ipv6.src)) | ||
740 | return -EMSGSIZE; | ||
741 | if (!ipv6_addr_any(&output->u.ipv6.dst) && | ||
742 | nla_put_in6_addr(skb, OVS_TUNNEL_KEY_ATTR_IPV6_DST, | ||
743 | &output->u.ipv6.dst)) | ||
744 | return -EMSGSIZE; | ||
745 | break; | ||
746 | } | ||
704 | if (output->tos && | 747 | if (output->tos && |
705 | nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos)) | 748 | nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->tos)) |
706 | return -EMSGSIZE; | 749 | return -EMSGSIZE; |
@@ -734,9 +777,10 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb, | |||
734 | return 0; | 777 | return 0; |
735 | } | 778 | } |
736 | 779 | ||
737 | static int ipv4_tun_to_nlattr(struct sk_buff *skb, | 780 | static int ip_tun_to_nlattr(struct sk_buff *skb, |
738 | const struct ip_tunnel_key *output, | 781 | const struct ip_tunnel_key *output, |
739 | const void *tun_opts, int swkey_tun_opts_len) | 782 | const void *tun_opts, int swkey_tun_opts_len, |
783 | unsigned short tun_proto) | ||
740 | { | 784 | { |
741 | struct nlattr *nla; | 785 | struct nlattr *nla; |
742 | int err; | 786 | int err; |
@@ -745,7 +789,8 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb, | |||
745 | if (!nla) | 789 | if (!nla) |
746 | return -EMSGSIZE; | 790 | return -EMSGSIZE; |
747 | 791 | ||
748 | err = __ipv4_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len); | 792 | err = __ip_tun_to_nlattr(skb, output, tun_opts, swkey_tun_opts_len, |
793 | tun_proto); | ||
749 | if (err) | 794 | if (err) |
750 | return err; | 795 | return err; |
751 | 796 | ||
@@ -757,9 +802,10 @@ int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb, | |||
757 | const struct ip_tunnel_info *egress_tun_info, | 802 | const struct ip_tunnel_info *egress_tun_info, |
758 | const void *egress_tun_opts) | 803 | const void *egress_tun_opts) |
759 | { | 804 | { |
760 | return __ipv4_tun_to_nlattr(skb, &egress_tun_info->key, | 805 | return __ip_tun_to_nlattr(skb, &egress_tun_info->key, |
761 | egress_tun_opts, | 806 | egress_tun_opts, |
762 | egress_tun_info->options_len); | 807 | egress_tun_info->options_len, |
808 | ip_tunnel_info_af(egress_tun_info)); | ||
763 | } | 809 | } |
764 | 810 | ||
765 | static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, | 811 | static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, |
@@ -810,8 +856,8 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, | |||
810 | *attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); | 856 | *attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); |
811 | } | 857 | } |
812 | if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) { | 858 | if (*attrs & (1 << OVS_KEY_ATTR_TUNNEL)) { |
813 | if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, | 859 | if (ip_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, |
814 | is_mask, log) < 0) | 860 | is_mask, log) < 0) |
815 | return -EINVAL; | 861 | return -EINVAL; |
816 | *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL); | 862 | *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL); |
817 | } | 863 | } |
@@ -1377,8 +1423,8 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, | |||
1377 | if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT) | 1423 | if (output->tun_key.tun_flags & TUNNEL_OPTIONS_PRESENT) |
1378 | opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len); | 1424 | opts = TUN_METADATA_OPTS(output, swkey->tun_opts_len); |
1379 | 1425 | ||
1380 | if (ipv4_tun_to_nlattr(skb, &output->tun_key, opts, | 1426 | if (ip_tun_to_nlattr(skb, &output->tun_key, opts, |
1381 | swkey->tun_opts_len)) | 1427 | swkey->tun_opts_len, swkey->tun_proto)) |
1382 | goto nla_put_failure; | 1428 | goto nla_put_failure; |
1383 | } | 1429 | } |
1384 | 1430 | ||
@@ -1881,7 +1927,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, | |||
1881 | int err = 0, start, opts_type; | 1927 | int err = 0, start, opts_type; |
1882 | 1928 | ||
1883 | ovs_match_init(&match, &key, NULL); | 1929 | ovs_match_init(&match, &key, NULL); |
1884 | opts_type = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log); | 1930 | opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log); |
1885 | if (opts_type < 0) | 1931 | if (opts_type < 0) |
1886 | return opts_type; | 1932 | return opts_type; |
1887 | 1933 | ||
@@ -2380,10 +2426,11 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) | |||
2380 | if (!start) | 2426 | if (!start) |
2381 | return -EMSGSIZE; | 2427 | return -EMSGSIZE; |
2382 | 2428 | ||
2383 | err = ipv4_tun_to_nlattr(skb, &tun_info->key, | 2429 | err = ip_tun_to_nlattr(skb, &tun_info->key, |
2384 | tun_info->options_len ? | 2430 | tun_info->options_len ? |
2385 | ip_tunnel_info_opts(tun_info) : NULL, | 2431 | ip_tunnel_info_opts(tun_info) : NULL, |
2386 | tun_info->options_len); | 2432 | tun_info->options_len, |
2433 | ip_tunnel_info_af(tun_info)); | ||
2387 | if (err) | 2434 | if (err) |
2388 | return err; | 2435 | return err; |
2389 | nla_nest_end(skb, start); | 2436 | nla_nest_end(skb, start); |