aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/sched/cls_flower.c64
1 files changed, 44 insertions, 20 deletions
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 6050e3caee31..2763176e369c 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -1459,6 +1459,28 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp,
1459 return 0; 1459 return 0;
1460} 1460}
1461 1461
1462static int fl_ht_insert_unique(struct cls_fl_filter *fnew,
1463 struct cls_fl_filter *fold,
1464 bool *in_ht)
1465{
1466 struct fl_flow_mask *mask = fnew->mask;
1467 int err;
1468
1469 err = rhashtable_insert_fast(&mask->ht,
1470 &fnew->ht_node,
1471 mask->filter_ht_params);
1472 if (err) {
1473 *in_ht = false;
1474 /* It is okay if filter with same key exists when
1475 * overwriting.
1476 */
1477 return fold && err == -EEXIST ? 0 : err;
1478 }
1479
1480 *in_ht = true;
1481 return 0;
1482}
1483
1462static int fl_change(struct net *net, struct sk_buff *in_skb, 1484static int fl_change(struct net *net, struct sk_buff *in_skb,
1463 struct tcf_proto *tp, unsigned long base, 1485 struct tcf_proto *tp, unsigned long base,
1464 u32 handle, struct nlattr **tca, 1486 u32 handle, struct nlattr **tca,
@@ -1470,6 +1492,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
1470 struct cls_fl_filter *fnew; 1492 struct cls_fl_filter *fnew;
1471 struct fl_flow_mask *mask; 1493 struct fl_flow_mask *mask;
1472 struct nlattr **tb; 1494 struct nlattr **tb;
1495 bool in_ht;
1473 int err; 1496 int err;
1474 1497
1475 if (!tca[TCA_OPTIONS]) { 1498 if (!tca[TCA_OPTIONS]) {
@@ -1528,10 +1551,14 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
1528 if (err) 1551 if (err)
1529 goto errout; 1552 goto errout;
1530 1553
1554 err = fl_ht_insert_unique(fnew, fold, &in_ht);
1555 if (err)
1556 goto errout_mask;
1557
1531 if (!tc_skip_hw(fnew->flags)) { 1558 if (!tc_skip_hw(fnew->flags)) {
1532 err = fl_hw_replace_filter(tp, fnew, rtnl_held, extack); 1559 err = fl_hw_replace_filter(tp, fnew, rtnl_held, extack);
1533 if (err) 1560 if (err)
1534 goto errout_mask; 1561 goto errout_ht;
1535 } 1562 }
1536 1563
1537 if (!tc_in_hw(fnew->flags)) 1564 if (!tc_in_hw(fnew->flags))
@@ -1557,10 +1584,17 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
1557 1584
1558 fnew->handle = handle; 1585 fnew->handle = handle;
1559 1586
1560 err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node, 1587 if (!in_ht) {
1561 fnew->mask->filter_ht_params); 1588 struct rhashtable_params params =
1562 if (err) 1589 fnew->mask->filter_ht_params;
1563 goto errout_hw; 1590
1591 err = rhashtable_insert_fast(&fnew->mask->ht,
1592 &fnew->ht_node,
1593 params);
1594 if (err)
1595 goto errout_hw;
1596 in_ht = true;
1597 }
1564 1598
1565 rhashtable_remove_fast(&fold->mask->ht, 1599 rhashtable_remove_fast(&fold->mask->ht,
1566 &fold->ht_node, 1600 &fold->ht_node,
@@ -1582,11 +1616,6 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
1582 refcount_dec(&fold->refcnt); 1616 refcount_dec(&fold->refcnt);
1583 __fl_put(fold); 1617 __fl_put(fold);
1584 } else { 1618 } else {
1585 if (__fl_lookup(fnew->mask, &fnew->mkey)) {
1586 err = -EEXIST;
1587 goto errout_hw;
1588 }
1589
1590 if (handle) { 1619 if (handle) {
1591 /* user specifies a handle and it doesn't exist */ 1620 /* user specifies a handle and it doesn't exist */
1592 err = idr_alloc_u32(&head->handle_idr, fnew, &handle, 1621 err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
@@ -1609,12 +1638,6 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
1609 goto errout_hw; 1638 goto errout_hw;
1610 1639
1611 fnew->handle = handle; 1640 fnew->handle = handle;
1612
1613 err = rhashtable_insert_fast(&fnew->mask->ht, &fnew->ht_node,
1614 fnew->mask->filter_ht_params);
1615 if (err)
1616 goto errout_idr;
1617
1618 list_add_tail_rcu(&fnew->list, &fnew->mask->filters); 1641 list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
1619 spin_unlock(&tp->lock); 1642 spin_unlock(&tp->lock);
1620 } 1643 }
@@ -1625,17 +1648,18 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
1625 kfree(mask); 1648 kfree(mask);
1626 return 0; 1649 return 0;
1627 1650
1628errout_idr:
1629 idr_remove(&head->handle_idr, fnew->handle);
1630errout_hw: 1651errout_hw:
1631 spin_unlock(&tp->lock); 1652 spin_unlock(&tp->lock);
1632 if (!tc_skip_hw(fnew->flags)) 1653 if (!tc_skip_hw(fnew->flags))
1633 fl_hw_destroy_filter(tp, fnew, rtnl_held, NULL); 1654 fl_hw_destroy_filter(tp, fnew, rtnl_held, NULL);
1655errout_ht:
1656 if (in_ht)
1657 rhashtable_remove_fast(&fnew->mask->ht, &fnew->ht_node,
1658 fnew->mask->filter_ht_params);
1634errout_mask: 1659errout_mask:
1635 fl_mask_put(head, fnew->mask, true); 1660 fl_mask_put(head, fnew->mask, true);
1636errout: 1661errout:
1637 tcf_exts_destroy(&fnew->exts); 1662 tcf_queue_work(&fnew->rwork, fl_destroy_filter_work);
1638 kfree(fnew);
1639errout_tb: 1663errout_tb:
1640 kfree(tb); 1664 kfree(tb);
1641errout_mask_alloc: 1665errout_mask_alloc: