Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

openvswitch: Make tunnel set action attach a metadata dst

Utilize the new metadata dst to attach encapsulation instructions to
the skb. The existing egress_tun_info via the OVS_CB() is left in
place until all tunnel vports have been converted to the new method.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Thomas Graf and committed by
David S. Miller
34ae932a 0dfbdf41

+82 -16
+9 -1
net/openvswitch/actions.c
··· 733 733 { 734 734 /* Only tunnel set execution is supported without a mask. */ 735 735 if (nla_type(a) == OVS_KEY_ATTR_TUNNEL_INFO) { 736 - OVS_CB(skb)->egress_tun_info = nla_data(a); 736 + struct ovs_tunnel_info *tun = nla_data(a); 737 + 738 + skb_dst_drop(skb); 739 + dst_hold((struct dst_entry *)tun->tun_dst); 740 + skb_dst_set(skb, (struct dst_entry *)tun->tun_dst); 741 + 742 + /* FIXME: Remove when all vports have been converted */ 743 + OVS_CB(skb)->egress_tun_info = &tun->tun_dst->u.tun_info; 744 + 737 745 return 0; 738 746 } 739 747
+4 -4
net/openvswitch/datapath.c
··· 1018 1018 } 1019 1019 ovs_unlock(); 1020 1020 1021 - ovs_nla_free_flow_actions(old_acts); 1021 + ovs_nla_free_flow_actions_rcu(old_acts); 1022 1022 ovs_flow_free(new_flow, false); 1023 1023 } 1024 1024 ··· 1030 1030 ovs_unlock(); 1031 1031 kfree_skb(reply); 1032 1032 err_kfree_acts: 1033 - kfree(acts); 1033 + ovs_nla_free_flow_actions(acts); 1034 1034 err_kfree_flow: 1035 1035 ovs_flow_free(new_flow, false); 1036 1036 error: ··· 1157 1157 if (reply) 1158 1158 ovs_notify(&dp_flow_genl_family, reply, info); 1159 1159 if (old_acts) 1160 - ovs_nla_free_flow_actions(old_acts); 1160 + ovs_nla_free_flow_actions_rcu(old_acts); 1161 1161 1162 1162 return 0; 1163 1163 ··· 1165 1165 ovs_unlock(); 1166 1166 kfree_skb(reply); 1167 1167 err_kfree_acts: 1168 - kfree(acts); 1168 + ovs_nla_free_flow_actions(acts); 1169 1169 error: 1170 1170 return error; 1171 1171 }
+5
net/openvswitch/flow.h
··· 33 33 #include <linux/flex_array.h> 34 34 #include <net/inet_ecn.h> 35 35 #include <net/ip_tunnels.h> 36 + #include <net/dst_metadata.h> 36 37 37 38 struct sk_buff; 38 39 ··· 45 44 (FIELD_SIZEOF(struct sw_flow_key, tun_opts) - opt_len) 46 45 #define TUN_METADATA_OPTS(flow_key, opt_len) \ 47 46 ((void *)((flow_key)->tun_opts + TUN_METADATA_OFFSET(opt_len))) 47 + 48 + struct ovs_tunnel_info { 49 + struct metadata_dst *tun_dst; 50 + }; 48 51 49 52 #define OVS_SW_FLOW_KEY_METADATA_SIZE \ 50 53 (offsetof(struct sw_flow_key, recirc_id) + \
+60 -10
net/openvswitch/flow_netlink.c
··· 1548 1548 return sfa; 1549 1549 } 1550 1550 1551 - /* Schedules 'sf_acts' to be freed after the next RCU grace period. 1552 - * The caller must hold rcu_read_lock for this to be sensible. */ 1551 + static void ovs_nla_free_set_action(const struct nlattr *a) 1552 + { 1553 + const struct nlattr *ovs_key = nla_data(a); 1554 + struct ovs_tunnel_info *ovs_tun; 1555 + 1556 + switch (nla_type(ovs_key)) { 1557 + case OVS_KEY_ATTR_TUNNEL_INFO: 1558 + ovs_tun = nla_data(ovs_key); 1559 + dst_release((struct dst_entry *)ovs_tun->tun_dst); 1560 + break; 1561 + } 1562 + } 1563 + 1553 1564 void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) 1554 1565 { 1555 - kfree_rcu(sf_acts, rcu); 1566 + const struct nlattr *a; 1567 + int rem; 1568 + 1569 + if (!sf_acts) 1570 + return; 1571 + 1572 + nla_for_each_attr(a, sf_acts->actions, sf_acts->actions_len, rem) { 1573 + switch (nla_type(a)) { 1574 + case OVS_ACTION_ATTR_SET: 1575 + ovs_nla_free_set_action(a); 1576 + break; 1577 + } 1578 + } 1579 + 1580 + kfree(sf_acts); 1581 + } 1582 + 1583 + static void __ovs_nla_free_flow_actions(struct rcu_head *head) 1584 + { 1585 + ovs_nla_free_flow_actions(container_of(head, struct sw_flow_actions, rcu)); 1586 + } 1587 + 1588 + /* Schedules 'sf_acts' to be freed after the next RCU grace period. 1589 + * The caller must hold rcu_read_lock for this to be sensible. */ 1590 + void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *sf_acts) 1591 + { 1592 + call_rcu(&sf_acts->rcu, __ovs_nla_free_flow_actions); 1556 1593 } 1557 1594 1558 1595 static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, ··· 1783 1746 { 1784 1747 struct sw_flow_match match; 1785 1748 struct sw_flow_key key; 1749 + struct metadata_dst *tun_dst; 1786 1750 struct ip_tunnel_info *tun_info; 1751 + struct ovs_tunnel_info *ovs_tun; 1787 1752 struct nlattr *a; 1788 1753 int err = 0, start, opts_type; 1789 1754 ··· 1810 1771 if (start < 0) 1811 1772 return start; 1812 1773 1813 - a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL, 1814 - sizeof(*tun_info) + key.tun_opts_len, log); 1815 - if (IS_ERR(a)) 1816 - return PTR_ERR(a); 1774 + tun_dst = metadata_dst_alloc(key.tun_opts_len, GFP_KERNEL); 1775 + if (!tun_dst) 1776 + return -ENOMEM; 1817 1777 1818 - tun_info = nla_data(a); 1778 + a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL, 1779 + sizeof(*ovs_tun), log); 1780 + if (IS_ERR(a)) { 1781 + dst_release((struct dst_entry *)tun_dst); 1782 + return PTR_ERR(a); 1783 + } 1784 + 1785 + ovs_tun = nla_data(a); 1786 + ovs_tun->tun_dst = tun_dst; 1787 + 1788 + tun_info = &tun_dst->u.tun_info; 1789 + tun_info->mode = IP_TUNNEL_INFO_TX; 1819 1790 tun_info->key = key.tun_key; 1820 1791 tun_info->options_len = key.tun_opts_len; 1821 1792 ··· 2226 2177 err = __ovs_nla_copy_actions(attr, key, 0, sfa, key->eth.type, 2227 2178 key->eth.tci, log); 2228 2179 if (err) 2229 - kfree(*sfa); 2180 + ovs_nla_free_flow_actions(*sfa); 2230 2181 2231 2182 return err; 2232 2183 } ··· 2276 2227 2277 2228 switch (key_type) { 2278 2229 case OVS_KEY_ATTR_TUNNEL_INFO: { 2279 - struct ip_tunnel_info *tun_info = nla_data(ovs_key); 2230 + struct ovs_tunnel_info *ovs_tun = nla_data(ovs_key); 2231 + struct ip_tunnel_info *tun_info = &ovs_tun->tun_dst->u.tun_info; 2280 2232 2281 2233 start = nla_nest_start(skb, OVS_ACTION_ATTR_SET); 2282 2234 if (!start)
+1
net/openvswitch/flow_netlink.h
··· 69 69 int len, struct sk_buff *skb); 70 70 71 71 void ovs_nla_free_flow_actions(struct sw_flow_actions *); 72 + void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *); 72 73 73 74 #endif /* flow_netlink.h */
+3 -1
net/openvswitch/flow_table.c
··· 18 18 19 19 #include "flow.h" 20 20 #include "datapath.h" 21 + #include "flow_netlink.h" 21 22 #include <linux/uaccess.h> 22 23 #include <linux/netdevice.h> 23 24 #include <linux/etherdevice.h> ··· 144 143 145 144 if (ovs_identifier_is_key(&flow->id)) 146 145 kfree(flow->id.unmasked_key); 147 - kfree((struct sw_flow_actions __force *)flow->sf_acts); 146 + if (flow->sf_acts) 147 + ovs_nla_free_flow_actions((struct sw_flow_actions __force *)flow->sf_acts); 148 148 for_each_node(node) 149 149 if (flow->stats[node]) 150 150 kmem_cache_free(flow_stats_cache,