diff options
Diffstat (limited to 'net/openvswitch/flow_netlink.c')
-rw-r--r-- | net/openvswitch/flow_netlink.c | 139 |
1 files changed, 121 insertions, 18 deletions
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 939bcb32100f..569309c49cc0 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <net/ip.h> | 46 | #include <net/ip.h> |
47 | #include <net/ipv6.h> | 47 | #include <net/ipv6.h> |
48 | #include <net/ndisc.h> | 48 | #include <net/ndisc.h> |
49 | #include <net/mpls.h> | ||
49 | 50 | ||
50 | #include "flow_netlink.h" | 51 | #include "flow_netlink.h" |
51 | 52 | ||
@@ -134,7 +135,8 @@ static bool match_validate(const struct sw_flow_match *match, | |||
134 | | (1 << OVS_KEY_ATTR_ICMP) | 135 | | (1 << OVS_KEY_ATTR_ICMP) |
135 | | (1 << OVS_KEY_ATTR_ICMPV6) | 136 | | (1 << OVS_KEY_ATTR_ICMPV6) |
136 | | (1 << OVS_KEY_ATTR_ARP) | 137 | | (1 << OVS_KEY_ATTR_ARP) |
137 | | (1 << OVS_KEY_ATTR_ND)); | 138 | | (1 << OVS_KEY_ATTR_ND) |
139 | | (1 << OVS_KEY_ATTR_MPLS)); | ||
138 | 140 | ||
139 | /* Always allowed mask fields. */ | 141 | /* Always allowed mask fields. */ |
140 | mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL) | 142 | mask_allowed |= ((1 << OVS_KEY_ATTR_TUNNEL) |
@@ -149,6 +151,12 @@ static bool match_validate(const struct sw_flow_match *match, | |||
149 | mask_allowed |= 1 << OVS_KEY_ATTR_ARP; | 151 | mask_allowed |= 1 << OVS_KEY_ATTR_ARP; |
150 | } | 152 | } |
151 | 153 | ||
154 | if (eth_p_mpls(match->key->eth.type)) { | ||
155 | key_expected |= 1 << OVS_KEY_ATTR_MPLS; | ||
156 | if (match->mask && (match->mask->key.eth.type == htons(0xffff))) | ||
157 | mask_allowed |= 1 << OVS_KEY_ATTR_MPLS; | ||
158 | } | ||
159 | |||
152 | if (match->key->eth.type == htons(ETH_P_IP)) { | 160 | if (match->key->eth.type == htons(ETH_P_IP)) { |
153 | key_expected |= 1 << OVS_KEY_ATTR_IPV4; | 161 | key_expected |= 1 << OVS_KEY_ATTR_IPV4; |
154 | if (match->mask && (match->mask->key.eth.type == htons(0xffff))) | 162 | if (match->mask && (match->mask->key.eth.type == htons(0xffff))) |
@@ -266,6 +274,7 @@ static const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { | |||
266 | [OVS_KEY_ATTR_RECIRC_ID] = sizeof(u32), | 274 | [OVS_KEY_ATTR_RECIRC_ID] = sizeof(u32), |
267 | [OVS_KEY_ATTR_DP_HASH] = sizeof(u32), | 275 | [OVS_KEY_ATTR_DP_HASH] = sizeof(u32), |
268 | [OVS_KEY_ATTR_TUNNEL] = -1, | 276 | [OVS_KEY_ATTR_TUNNEL] = -1, |
277 | [OVS_KEY_ATTR_MPLS] = sizeof(struct ovs_key_mpls), | ||
269 | }; | 278 | }; |
270 | 279 | ||
271 | static bool is_all_zero(const u8 *fp, size_t size) | 280 | static bool is_all_zero(const u8 *fp, size_t size) |
@@ -735,6 +744,16 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, | |||
735 | attrs &= ~(1 << OVS_KEY_ATTR_ARP); | 744 | attrs &= ~(1 << OVS_KEY_ATTR_ARP); |
736 | } | 745 | } |
737 | 746 | ||
747 | if (attrs & (1 << OVS_KEY_ATTR_MPLS)) { | ||
748 | const struct ovs_key_mpls *mpls_key; | ||
749 | |||
750 | mpls_key = nla_data(a[OVS_KEY_ATTR_MPLS]); | ||
751 | SW_FLOW_KEY_PUT(match, mpls.top_lse, | ||
752 | mpls_key->mpls_lse, is_mask); | ||
753 | |||
754 | attrs &= ~(1 << OVS_KEY_ATTR_MPLS); | ||
755 | } | ||
756 | |||
738 | if (attrs & (1 << OVS_KEY_ATTR_TCP)) { | 757 | if (attrs & (1 << OVS_KEY_ATTR_TCP)) { |
739 | const struct ovs_key_tcp *tcp_key; | 758 | const struct ovs_key_tcp *tcp_key; |
740 | 759 | ||
@@ -1140,6 +1159,14 @@ int ovs_nla_put_flow(const struct sw_flow_key *swkey, | |||
1140 | arp_key->arp_op = htons(output->ip.proto); | 1159 | arp_key->arp_op = htons(output->ip.proto); |
1141 | ether_addr_copy(arp_key->arp_sha, output->ipv4.arp.sha); | 1160 | ether_addr_copy(arp_key->arp_sha, output->ipv4.arp.sha); |
1142 | ether_addr_copy(arp_key->arp_tha, output->ipv4.arp.tha); | 1161 | ether_addr_copy(arp_key->arp_tha, output->ipv4.arp.tha); |
1162 | } else if (eth_p_mpls(swkey->eth.type)) { | ||
1163 | struct ovs_key_mpls *mpls_key; | ||
1164 | |||
1165 | nla = nla_reserve(skb, OVS_KEY_ATTR_MPLS, sizeof(*mpls_key)); | ||
1166 | if (!nla) | ||
1167 | goto nla_put_failure; | ||
1168 | mpls_key = nla_data(nla); | ||
1169 | mpls_key->mpls_lse = output->mpls.top_lse; | ||
1143 | } | 1170 | } |
1144 | 1171 | ||
1145 | if ((swkey->eth.type == htons(ETH_P_IP) || | 1172 | if ((swkey->eth.type == htons(ETH_P_IP) || |
@@ -1336,9 +1363,15 @@ static inline void add_nested_action_end(struct sw_flow_actions *sfa, | |||
1336 | a->nla_len = sfa->actions_len - st_offset; | 1363 | a->nla_len = sfa->actions_len - st_offset; |
1337 | } | 1364 | } |
1338 | 1365 | ||
1366 | static int ovs_nla_copy_actions__(const struct nlattr *attr, | ||
1367 | const struct sw_flow_key *key, | ||
1368 | int depth, struct sw_flow_actions **sfa, | ||
1369 | __be16 eth_type, __be16 vlan_tci); | ||
1370 | |||
1339 | static int validate_and_copy_sample(const struct nlattr *attr, | 1371 | static int validate_and_copy_sample(const struct nlattr *attr, |
1340 | const struct sw_flow_key *key, int depth, | 1372 | const struct sw_flow_key *key, int depth, |
1341 | struct sw_flow_actions **sfa) | 1373 | struct sw_flow_actions **sfa, |
1374 | __be16 eth_type, __be16 vlan_tci) | ||
1342 | { | 1375 | { |
1343 | const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1]; | 1376 | const struct nlattr *attrs[OVS_SAMPLE_ATTR_MAX + 1]; |
1344 | const struct nlattr *probability, *actions; | 1377 | const struct nlattr *probability, *actions; |
@@ -1375,7 +1408,8 @@ static int validate_and_copy_sample(const struct nlattr *attr, | |||
1375 | if (st_acts < 0) | 1408 | if (st_acts < 0) |
1376 | return st_acts; | 1409 | return st_acts; |
1377 | 1410 | ||
1378 | err = ovs_nla_copy_actions(actions, key, depth + 1, sfa); | 1411 | err = ovs_nla_copy_actions__(actions, key, depth + 1, sfa, |
1412 | eth_type, vlan_tci); | ||
1379 | if (err) | 1413 | if (err) |
1380 | return err; | 1414 | return err; |
1381 | 1415 | ||
@@ -1385,10 +1419,10 @@ static int validate_and_copy_sample(const struct nlattr *attr, | |||
1385 | return 0; | 1419 | return 0; |
1386 | } | 1420 | } |
1387 | 1421 | ||
1388 | static int validate_tp_port(const struct sw_flow_key *flow_key) | 1422 | static int validate_tp_port(const struct sw_flow_key *flow_key, |
1423 | __be16 eth_type) | ||
1389 | { | 1424 | { |
1390 | if ((flow_key->eth.type == htons(ETH_P_IP) || | 1425 | if ((eth_type == htons(ETH_P_IP) || eth_type == htons(ETH_P_IPV6)) && |
1391 | flow_key->eth.type == htons(ETH_P_IPV6)) && | ||
1392 | (flow_key->tp.src || flow_key->tp.dst)) | 1426 | (flow_key->tp.src || flow_key->tp.dst)) |
1393 | return 0; | 1427 | return 0; |
1394 | 1428 | ||
@@ -1483,7 +1517,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, | |||
1483 | static int validate_set(const struct nlattr *a, | 1517 | static int validate_set(const struct nlattr *a, |
1484 | const struct sw_flow_key *flow_key, | 1518 | const struct sw_flow_key *flow_key, |
1485 | struct sw_flow_actions **sfa, | 1519 | struct sw_flow_actions **sfa, |
1486 | bool *set_tun) | 1520 | bool *set_tun, __be16 eth_type) |
1487 | { | 1521 | { |
1488 | const struct nlattr *ovs_key = nla_data(a); | 1522 | const struct nlattr *ovs_key = nla_data(a); |
1489 | int key_type = nla_type(ovs_key); | 1523 | int key_type = nla_type(ovs_key); |
@@ -1508,6 +1542,9 @@ static int validate_set(const struct nlattr *a, | |||
1508 | break; | 1542 | break; |
1509 | 1543 | ||
1510 | case OVS_KEY_ATTR_TUNNEL: | 1544 | case OVS_KEY_ATTR_TUNNEL: |
1545 | if (eth_p_mpls(eth_type)) | ||
1546 | return -EINVAL; | ||
1547 | |||
1511 | *set_tun = true; | 1548 | *set_tun = true; |
1512 | err = validate_and_copy_set_tun(a, sfa); | 1549 | err = validate_and_copy_set_tun(a, sfa); |
1513 | if (err) | 1550 | if (err) |
@@ -1515,7 +1552,7 @@ static int validate_set(const struct nlattr *a, | |||
1515 | break; | 1552 | break; |
1516 | 1553 | ||
1517 | case OVS_KEY_ATTR_IPV4: | 1554 | case OVS_KEY_ATTR_IPV4: |
1518 | if (flow_key->eth.type != htons(ETH_P_IP)) | 1555 | if (eth_type != htons(ETH_P_IP)) |
1519 | return -EINVAL; | 1556 | return -EINVAL; |
1520 | 1557 | ||
1521 | if (!flow_key->ip.proto) | 1558 | if (!flow_key->ip.proto) |
@@ -1531,7 +1568,7 @@ static int validate_set(const struct nlattr *a, | |||
1531 | break; | 1568 | break; |
1532 | 1569 | ||
1533 | case OVS_KEY_ATTR_IPV6: | 1570 | case OVS_KEY_ATTR_IPV6: |
1534 | if (flow_key->eth.type != htons(ETH_P_IPV6)) | 1571 | if (eth_type != htons(ETH_P_IPV6)) |
1535 | return -EINVAL; | 1572 | return -EINVAL; |
1536 | 1573 | ||
1537 | if (!flow_key->ip.proto) | 1574 | if (!flow_key->ip.proto) |
@@ -1553,19 +1590,24 @@ static int validate_set(const struct nlattr *a, | |||
1553 | if (flow_key->ip.proto != IPPROTO_TCP) | 1590 | if (flow_key->ip.proto != IPPROTO_TCP) |
1554 | return -EINVAL; | 1591 | return -EINVAL; |
1555 | 1592 | ||
1556 | return validate_tp_port(flow_key); | 1593 | return validate_tp_port(flow_key, eth_type); |
1557 | 1594 | ||
1558 | case OVS_KEY_ATTR_UDP: | 1595 | case OVS_KEY_ATTR_UDP: |
1559 | if (flow_key->ip.proto != IPPROTO_UDP) | 1596 | if (flow_key->ip.proto != IPPROTO_UDP) |
1560 | return -EINVAL; | 1597 | return -EINVAL; |
1561 | 1598 | ||
1562 | return validate_tp_port(flow_key); | 1599 | return validate_tp_port(flow_key, eth_type); |
1600 | |||
1601 | case OVS_KEY_ATTR_MPLS: | ||
1602 | if (!eth_p_mpls(eth_type)) | ||
1603 | return -EINVAL; | ||
1604 | break; | ||
1563 | 1605 | ||
1564 | case OVS_KEY_ATTR_SCTP: | 1606 | case OVS_KEY_ATTR_SCTP: |
1565 | if (flow_key->ip.proto != IPPROTO_SCTP) | 1607 | if (flow_key->ip.proto != IPPROTO_SCTP) |
1566 | return -EINVAL; | 1608 | return -EINVAL; |
1567 | 1609 | ||
1568 | return validate_tp_port(flow_key); | 1610 | return validate_tp_port(flow_key, eth_type); |
1569 | 1611 | ||
1570 | default: | 1612 | default: |
1571 | return -EINVAL; | 1613 | return -EINVAL; |
@@ -1609,12 +1651,13 @@ static int copy_action(const struct nlattr *from, | |||
1609 | return 0; | 1651 | return 0; |
1610 | } | 1652 | } |
1611 | 1653 | ||
1612 | int ovs_nla_copy_actions(const struct nlattr *attr, | 1654 | static int ovs_nla_copy_actions__(const struct nlattr *attr, |
1613 | const struct sw_flow_key *key, | 1655 | const struct sw_flow_key *key, |
1614 | int depth, | 1656 | int depth, struct sw_flow_actions **sfa, |
1615 | struct sw_flow_actions **sfa) | 1657 | __be16 eth_type, __be16 vlan_tci) |
1616 | { | 1658 | { |
1617 | const struct nlattr *a; | 1659 | const struct nlattr *a; |
1660 | bool out_tnl_port = false; | ||
1618 | int rem, err; | 1661 | int rem, err; |
1619 | 1662 | ||
1620 | if (depth >= SAMPLE_ACTION_DEPTH) | 1663 | if (depth >= SAMPLE_ACTION_DEPTH) |
@@ -1626,6 +1669,8 @@ int ovs_nla_copy_actions(const struct nlattr *attr, | |||
1626 | [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32), | 1669 | [OVS_ACTION_ATTR_OUTPUT] = sizeof(u32), |
1627 | [OVS_ACTION_ATTR_RECIRC] = sizeof(u32), | 1670 | [OVS_ACTION_ATTR_RECIRC] = sizeof(u32), |
1628 | [OVS_ACTION_ATTR_USERSPACE] = (u32)-1, | 1671 | [OVS_ACTION_ATTR_USERSPACE] = (u32)-1, |
1672 | [OVS_ACTION_ATTR_PUSH_MPLS] = sizeof(struct ovs_action_push_mpls), | ||
1673 | [OVS_ACTION_ATTR_POP_MPLS] = sizeof(__be16), | ||
1629 | [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan), | 1674 | [OVS_ACTION_ATTR_PUSH_VLAN] = sizeof(struct ovs_action_push_vlan), |
1630 | [OVS_ACTION_ATTR_POP_VLAN] = 0, | 1675 | [OVS_ACTION_ATTR_POP_VLAN] = 0, |
1631 | [OVS_ACTION_ATTR_SET] = (u32)-1, | 1676 | [OVS_ACTION_ATTR_SET] = (u32)-1, |
@@ -1655,6 +1700,8 @@ int ovs_nla_copy_actions(const struct nlattr *attr, | |||
1655 | case OVS_ACTION_ATTR_OUTPUT: | 1700 | case OVS_ACTION_ATTR_OUTPUT: |
1656 | if (nla_get_u32(a) >= DP_MAX_PORTS) | 1701 | if (nla_get_u32(a) >= DP_MAX_PORTS) |
1657 | return -EINVAL; | 1702 | return -EINVAL; |
1703 | out_tnl_port = false; | ||
1704 | |||
1658 | break; | 1705 | break; |
1659 | 1706 | ||
1660 | case OVS_ACTION_ATTR_HASH: { | 1707 | case OVS_ACTION_ATTR_HASH: { |
@@ -1671,6 +1718,7 @@ int ovs_nla_copy_actions(const struct nlattr *attr, | |||
1671 | } | 1718 | } |
1672 | 1719 | ||
1673 | case OVS_ACTION_ATTR_POP_VLAN: | 1720 | case OVS_ACTION_ATTR_POP_VLAN: |
1721 | vlan_tci = htons(0); | ||
1674 | break; | 1722 | break; |
1675 | 1723 | ||
1676 | case OVS_ACTION_ATTR_PUSH_VLAN: | 1724 | case OVS_ACTION_ATTR_PUSH_VLAN: |
@@ -1679,19 +1727,66 @@ int ovs_nla_copy_actions(const struct nlattr *attr, | |||
1679 | return -EINVAL; | 1727 | return -EINVAL; |
1680 | if (!(vlan->vlan_tci & htons(VLAN_TAG_PRESENT))) | 1728 | if (!(vlan->vlan_tci & htons(VLAN_TAG_PRESENT))) |
1681 | return -EINVAL; | 1729 | return -EINVAL; |
1730 | vlan_tci = vlan->vlan_tci; | ||
1682 | break; | 1731 | break; |
1683 | 1732 | ||
1684 | case OVS_ACTION_ATTR_RECIRC: | 1733 | case OVS_ACTION_ATTR_RECIRC: |
1685 | break; | 1734 | break; |
1686 | 1735 | ||
1736 | case OVS_ACTION_ATTR_PUSH_MPLS: { | ||
1737 | const struct ovs_action_push_mpls *mpls = nla_data(a); | ||
1738 | |||
1739 | /* Networking stack do not allow simultaneous Tunnel | ||
1740 | * and MPLS GSO. | ||
1741 | */ | ||
1742 | if (out_tnl_port) | ||
1743 | return -EINVAL; | ||
1744 | |||
1745 | if (!eth_p_mpls(mpls->mpls_ethertype)) | ||
1746 | return -EINVAL; | ||
1747 | /* Prohibit push MPLS other than to a white list | ||
1748 | * for packets that have a known tag order. | ||
1749 | */ | ||
1750 | if (vlan_tci & htons(VLAN_TAG_PRESENT) || | ||
1751 | (eth_type != htons(ETH_P_IP) && | ||
1752 | eth_type != htons(ETH_P_IPV6) && | ||
1753 | eth_type != htons(ETH_P_ARP) && | ||
1754 | eth_type != htons(ETH_P_RARP) && | ||
1755 | !eth_p_mpls(eth_type))) | ||
1756 | return -EINVAL; | ||
1757 | eth_type = mpls->mpls_ethertype; | ||
1758 | break; | ||
1759 | } | ||
1760 | |||
1761 | case OVS_ACTION_ATTR_POP_MPLS: | ||
1762 | if (vlan_tci & htons(VLAN_TAG_PRESENT) || | ||
1763 | !eth_p_mpls(eth_type)) | ||
1764 | return -EINVAL; | ||
1765 | |||
1766 | /* Disallow subsequent L2.5+ set and mpls_pop actions | ||
1767 | * as there is no check here to ensure that the new | ||
1768 | * eth_type is valid and thus set actions could | ||
1769 | * write off the end of the packet or otherwise | ||
1770 | * corrupt it. | ||
1771 | * | ||
1772 | * Support for these actions is planned using packet | ||
1773 | * recirculation. | ||
1774 | */ | ||
1775 | eth_type = htons(0); | ||
1776 | break; | ||
1777 | |||
1687 | case OVS_ACTION_ATTR_SET: | 1778 | case OVS_ACTION_ATTR_SET: |
1688 | err = validate_set(a, key, sfa, &skip_copy); | 1779 | err = validate_set(a, key, sfa, |
1780 | &out_tnl_port, eth_type); | ||
1689 | if (err) | 1781 | if (err) |
1690 | return err; | 1782 | return err; |
1783 | |||
1784 | skip_copy = out_tnl_port; | ||
1691 | break; | 1785 | break; |
1692 | 1786 | ||
1693 | case OVS_ACTION_ATTR_SAMPLE: | 1787 | case OVS_ACTION_ATTR_SAMPLE: |
1694 | err = validate_and_copy_sample(a, key, depth, sfa); | 1788 | err = validate_and_copy_sample(a, key, depth, sfa, |
1789 | eth_type, vlan_tci); | ||
1695 | if (err) | 1790 | if (err) |
1696 | return err; | 1791 | return err; |
1697 | skip_copy = true; | 1792 | skip_copy = true; |
@@ -1713,6 +1808,14 @@ int ovs_nla_copy_actions(const struct nlattr *attr, | |||
1713 | return 0; | 1808 | return 0; |
1714 | } | 1809 | } |
1715 | 1810 | ||
1811 | int ovs_nla_copy_actions(const struct nlattr *attr, | ||
1812 | const struct sw_flow_key *key, | ||
1813 | struct sw_flow_actions **sfa) | ||
1814 | { | ||
1815 | return ovs_nla_copy_actions__(attr, key, 0, sfa, key->eth.type, | ||
1816 | key->eth.tci); | ||
1817 | } | ||
1818 | |||
1716 | static int sample_action_to_attr(const struct nlattr *attr, struct sk_buff *skb) | 1819 | static int sample_action_to_attr(const struct nlattr *attr, struct sk_buff *skb) |
1717 | { | 1820 | { |
1718 | const struct nlattr *a; | 1821 | const struct nlattr *a; |