]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/dcb/dcbnl.c
Merge branches 'irq-urgent-for-linus', 'x86-urgent-for-linus' and 'sched-urgent-for...
[karo-tx-linux.git] / net / dcb / dcbnl.c
index ed1bb8c65a9e05c27ed340b157252974b6fffe9c..3cb56af4e13c9945927f67d854c2f82467d8259a 100644 (file)
@@ -1166,64 +1166,6 @@ err:
        return ret;
 }
 
-/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
- * be completed the entire msg is aborted and error value is returned.
- * No attempt is made to reconcile the case where only part of the
- * cmd can be completed.
- */
-static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
-                         u32 pid, u32 seq, u16 flags)
-{
-       const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
-       struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
-       int err = -EOPNOTSUPP;
-
-       if (!ops)
-               goto err;
-
-       err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
-                              tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
-       if (err)
-               goto err;
-
-       if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
-               struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
-               err = ops->ieee_setets(netdev, ets);
-               if (err)
-                       goto err;
-       }
-
-       if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
-               struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
-               err = ops->ieee_setpfc(netdev, pfc);
-               if (err)
-                       goto err;
-       }
-
-       if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
-               struct nlattr *attr;
-               int rem;
-
-               nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
-                       struct dcb_app *app_data;
-                       if (nla_type(attr) != DCB_ATTR_IEEE_APP)
-                               continue;
-                       app_data = nla_data(attr);
-                       if (ops->ieee_setapp)
-                               err = ops->ieee_setapp(netdev, app_data);
-                       else
-                               err = dcb_setapp(netdev, app_data);
-                       if (err)
-                               goto err;
-               }
-       }
-
-err:
-       dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
-                   pid, seq, flags);
-       return err;
-}
-
 static int dcbnl_build_peer_app(struct net_device *netdev, struct sk_buff* skb,
                                int app_nested_type, int app_info_type,
                                int app_entry_type)
@@ -1279,29 +1221,13 @@ nla_put_failure:
 }
 
 /* Handle IEEE 802.1Qaz GET commands. */
-static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
-                         u32 pid, u32 seq, u16 flags)
+static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
 {
-       struct sk_buff *skb;
-       struct nlmsghdr *nlh;
-       struct dcbmsg *dcb;
        struct nlattr *ieee, *app;
        struct dcb_app_type *itr;
        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
-       int err;
-
-       if (!ops)
-               return -EOPNOTSUPP;
-
-       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!skb)
-               return -ENOBUFS;
-
-       nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
-
-       dcb = NLMSG_DATA(nlh);
-       dcb->dcb_family = AF_UNSPEC;
-       dcb->cmd = DCB_CMD_IEEE_GET;
+       int dcbx;
+       int err = -EMSGSIZE;
 
        NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
 
@@ -1338,6 +1264,12 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
                        }
                }
        }
+
+       if (netdev->dcbnl_ops->getdcbx)
+               dcbx = netdev->dcbnl_ops->getdcbx(netdev);
+       else
+               dcbx = -EOPNOTSUPP;
+
        spin_unlock(&dcb_lock);
        nla_nest_end(skb, app);
 
@@ -1366,16 +1298,413 @@ static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
        }
 
        nla_nest_end(skb, ieee);
-       nlmsg_end(skb, nlh);
+       if (dcbx >= 0) {
+               err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
+               if (err)
+                       goto nla_put_failure;
+       }
+
+       return 0;
 
-       return rtnl_unicast(skb, &init_net, pid);
 nla_put_failure:
-       nlmsg_cancel(skb, nlh);
-nlmsg_failure:
-       kfree_skb(skb);
-       return -1;
+       return err;
 }
 
+static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
+                            int dir)
+{
+       u8 pgid, up_map, prio, tc_pct;
+       const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
+       int i = dir ? DCB_ATTR_CEE_TX_PG : DCB_ATTR_CEE_RX_PG;
+       struct nlattr *pg = nla_nest_start(skb, i);
+
+       if (!pg)
+               goto nla_put_failure;
+
+       for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) {
+               struct nlattr *tc_nest = nla_nest_start(skb, i);
+
+               if (!tc_nest)
+                       goto nla_put_failure;
+
+               pgid = DCB_ATTR_VALUE_UNDEFINED;
+               prio = DCB_ATTR_VALUE_UNDEFINED;
+               tc_pct = DCB_ATTR_VALUE_UNDEFINED;
+               up_map = DCB_ATTR_VALUE_UNDEFINED;
+
+               if (!dir)
+                       ops->getpgtccfgrx(dev, i - DCB_PG_ATTR_TC_0,
+                                         &prio, &pgid, &tc_pct, &up_map);
+               else
+                       ops->getpgtccfgtx(dev, i - DCB_PG_ATTR_TC_0,
+                                         &prio, &pgid, &tc_pct, &up_map);
+
+               NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_PGID, pgid);
+               NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_UP_MAPPING, up_map);
+               NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_STRICT_PRIO, prio);
+               NLA_PUT_U8(skb, DCB_TC_ATTR_PARAM_BW_PCT, tc_pct);
+               nla_nest_end(skb, tc_nest);
+       }
+
+       for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) {
+               tc_pct = DCB_ATTR_VALUE_UNDEFINED;
+
+               if (!dir)
+                       ops->getpgbwgcfgrx(dev, i - DCB_PG_ATTR_BW_ID_0,
+                                          &tc_pct);
+               else
+                       ops->getpgbwgcfgtx(dev, i - DCB_PG_ATTR_BW_ID_0,
+                                          &tc_pct);
+               NLA_PUT_U8(skb, i, tc_pct);
+       }
+       nla_nest_end(skb, pg);
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+static int dcbnl_cee_fill(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct nlattr *cee, *app;
+       struct dcb_app_type *itr;
+       const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
+       int dcbx, i, err = -EMSGSIZE;
+       u8 value;
+
+       NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
+
+       cee = nla_nest_start(skb, DCB_ATTR_CEE);
+       if (!cee)
+               goto nla_put_failure;
+
+       /* local pg */
+       if (ops->getpgtccfgtx && ops->getpgbwgcfgtx) {
+               err = dcbnl_cee_pg_fill(skb, netdev, 1);
+               if (err)
+                       goto nla_put_failure;
+       }
+
+       if (ops->getpgtccfgrx && ops->getpgbwgcfgrx) {
+               err = dcbnl_cee_pg_fill(skb, netdev, 0);
+               if (err)
+                       goto nla_put_failure;
+       }
+
+       /* local pfc */
+       if (ops->getpfccfg) {
+               struct nlattr *pfc_nest = nla_nest_start(skb, DCB_ATTR_CEE_PFC);
+
+               if (!pfc_nest)
+                       goto nla_put_failure;
+
+               for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) {
+                       ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, &value);
+                       NLA_PUT_U8(skb, i, value);
+               }
+               nla_nest_end(skb, pfc_nest);
+       }
+
+       /* local app */
+       spin_lock(&dcb_lock);
+       app = nla_nest_start(skb, DCB_ATTR_CEE_APP_TABLE);
+       if (!app)
+               goto dcb_unlock;
+
+       list_for_each_entry(itr, &dcb_app_list, list) {
+               if (strncmp(itr->name, netdev->name, IFNAMSIZ) == 0) {
+                       struct nlattr *app_nest = nla_nest_start(skb,
+                                                                DCB_ATTR_APP);
+                       if (!app_nest)
+                               goto dcb_unlock;
+
+                       err = nla_put_u8(skb, DCB_APP_ATTR_IDTYPE,
+                                        itr->app.selector);
+                       if (err)
+                               goto dcb_unlock;
+
+                       err = nla_put_u16(skb, DCB_APP_ATTR_ID,
+                                         itr->app.protocol);
+                       if (err)
+                               goto dcb_unlock;
+
+                       err = nla_put_u8(skb, DCB_APP_ATTR_PRIORITY,
+                                        itr->app.priority);
+                       if (err)
+                               goto dcb_unlock;
+
+                       nla_nest_end(skb, app_nest);
+               }
+       }
+       nla_nest_end(skb, app);
+
+       if (netdev->dcbnl_ops->getdcbx)
+               dcbx = netdev->dcbnl_ops->getdcbx(netdev);
+       else
+               dcbx = -EOPNOTSUPP;
+
+       spin_unlock(&dcb_lock);
+
+       /* features flags */
+       if (ops->getfeatcfg) {
+               struct nlattr *feat = nla_nest_start(skb, DCB_ATTR_CEE_FEAT);
+               if (!feat)
+                       goto nla_put_failure;
+
+               for (i = DCB_FEATCFG_ATTR_ALL + 1; i <= DCB_FEATCFG_ATTR_MAX;
+                    i++)
+                       if (!ops->getfeatcfg(netdev, i, &value))
+                               NLA_PUT_U8(skb, i, value);
+
+               nla_nest_end(skb, feat);
+       }
+
+       /* peer info if available */
+       if (ops->cee_peer_getpg) {
+               struct cee_pg pg;
+               err = ops->cee_peer_getpg(netdev, &pg);
+               if (!err)
+                       NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg);
+       }
+
+       if (ops->cee_peer_getpfc) {
+               struct cee_pfc pfc;
+               err = ops->cee_peer_getpfc(netdev, &pfc);
+               if (!err)
+                       NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc);
+       }
+
+       if (ops->peer_getappinfo && ops->peer_getapptable) {
+               err = dcbnl_build_peer_app(netdev, skb,
+                                          DCB_ATTR_CEE_PEER_APP_TABLE,
+                                          DCB_ATTR_CEE_PEER_APP_INFO,
+                                          DCB_ATTR_CEE_PEER_APP);
+               if (err)
+                       goto nla_put_failure;
+       }
+       nla_nest_end(skb, cee);
+
+       /* DCBX state */
+       if (dcbx >= 0) {
+               err = nla_put_u8(skb, DCB_ATTR_DCBX, dcbx);
+               if (err)
+                       goto nla_put_failure;
+       }
+       return 0;
+
+dcb_unlock:
+       spin_unlock(&dcb_lock);
+nla_put_failure:
+       return err;
+}
+
+static int dcbnl_notify(struct net_device *dev, int event, int cmd,
+                       u32 seq, u32 pid, int dcbx_ver)
+{
+       struct net *net = dev_net(dev);
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       struct dcbmsg *dcb;
+       const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
+       int err;
+
+       if (!ops)
+               return -EOPNOTSUPP;
+
+       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOBUFS;
+
+       nlh = nlmsg_put(skb, pid, 0, event, sizeof(*dcb), 0);
+       if (nlh == NULL) {
+               nlmsg_free(skb);
+               return -EMSGSIZE;
+       }
+
+       dcb = NLMSG_DATA(nlh);
+       dcb->dcb_family = AF_UNSPEC;
+       dcb->cmd = cmd;
+
+       if (dcbx_ver == DCB_CAP_DCBX_VER_IEEE)
+               err = dcbnl_ieee_fill(skb, dev);
+       else
+               err = dcbnl_cee_fill(skb, dev);
+
+       if (err < 0) {
+               /* Report error to broadcast listeners */
+               nlmsg_cancel(skb, nlh);
+               kfree_skb(skb);
+               rtnl_set_sk_err(net, RTNLGRP_DCB, err);
+       } else {
+               /* End nlmsg and notify broadcast listeners */
+               nlmsg_end(skb, nlh);
+               rtnl_notify(skb, net, 0, RTNLGRP_DCB, NULL, GFP_KERNEL);
+       }
+
+       return err;
+}
+
+int dcbnl_ieee_notify(struct net_device *dev, int event, int cmd,
+                     u32 seq, u32 pid)
+{
+       return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_IEEE);
+}
+EXPORT_SYMBOL(dcbnl_ieee_notify);
+
+int dcbnl_cee_notify(struct net_device *dev, int event, int cmd,
+                    u32 seq, u32 pid)
+{
+       return dcbnl_notify(dev, event, cmd, seq, pid, DCB_CAP_DCBX_VER_CEE);
+}
+EXPORT_SYMBOL(dcbnl_cee_notify);
+
+/* Handle IEEE 802.1Qaz SET commands. If any requested operation can not
+ * be completed the entire msg is aborted and error value is returned.
+ * No attempt is made to reconcile the case where only part of the
+ * cmd can be completed.
+ */
+static int dcbnl_ieee_set(struct net_device *netdev, struct nlattr **tb,
+                         u32 pid, u32 seq, u16 flags)
+{
+       const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
+       struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
+       int err = -EOPNOTSUPP;
+
+       if (!ops)
+               return err;
+
+       if (!tb[DCB_ATTR_IEEE])
+               return -EINVAL;
+
+       err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
+                              tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
+       if (err)
+               return err;
+
+       if (ieee[DCB_ATTR_IEEE_ETS] && ops->ieee_setets) {
+               struct ieee_ets *ets = nla_data(ieee[DCB_ATTR_IEEE_ETS]);
+               err = ops->ieee_setets(netdev, ets);
+               if (err)
+                       goto err;
+       }
+
+       if (ieee[DCB_ATTR_IEEE_PFC] && ops->ieee_setpfc) {
+               struct ieee_pfc *pfc = nla_data(ieee[DCB_ATTR_IEEE_PFC]);
+               err = ops->ieee_setpfc(netdev, pfc);
+               if (err)
+                       goto err;
+       }
+
+       if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
+               struct nlattr *attr;
+               int rem;
+
+               nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
+                       struct dcb_app *app_data;
+                       if (nla_type(attr) != DCB_ATTR_IEEE_APP)
+                               continue;
+                       app_data = nla_data(attr);
+                       if (ops->ieee_setapp)
+                               err = ops->ieee_setapp(netdev, app_data);
+                       else
+                               err = dcb_ieee_setapp(netdev, app_data);
+                       if (err)
+                               goto err;
+               }
+       }
+
+err:
+       dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_SET, DCB_ATTR_IEEE,
+                   pid, seq, flags);
+       dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, seq, 0);
+       return err;
+}
+
+static int dcbnl_ieee_get(struct net_device *netdev, struct nlattr **tb,
+                         u32 pid, u32 seq, u16 flags)
+{
+       struct net *net = dev_net(netdev);
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       struct dcbmsg *dcb;
+       const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
+       int err;
+
+       if (!ops)
+               return -EOPNOTSUPP;
+
+       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOBUFS;
+
+       nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+       if (nlh == NULL) {
+               nlmsg_free(skb);
+               return -EMSGSIZE;
+       }
+
+       dcb = NLMSG_DATA(nlh);
+       dcb->dcb_family = AF_UNSPEC;
+       dcb->cmd = DCB_CMD_IEEE_GET;
+
+       err = dcbnl_ieee_fill(skb, netdev);
+
+       if (err < 0) {
+               nlmsg_cancel(skb, nlh);
+               kfree_skb(skb);
+       } else {
+               nlmsg_end(skb, nlh);
+               err = rtnl_unicast(skb, net, pid);
+       }
+
+       return err;
+}
+
+static int dcbnl_ieee_del(struct net_device *netdev, struct nlattr **tb,
+                         u32 pid, u32 seq, u16 flags)
+{
+       const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
+       struct nlattr *ieee[DCB_ATTR_IEEE_MAX + 1];
+       int err = -EOPNOTSUPP;
+
+       if (!ops)
+               return -EOPNOTSUPP;
+
+       if (!tb[DCB_ATTR_IEEE])
+               return -EINVAL;
+
+       err = nla_parse_nested(ieee, DCB_ATTR_IEEE_MAX,
+                              tb[DCB_ATTR_IEEE], dcbnl_ieee_policy);
+       if (err)
+               return err;
+
+       if (ieee[DCB_ATTR_IEEE_APP_TABLE]) {
+               struct nlattr *attr;
+               int rem;
+
+               nla_for_each_nested(attr, ieee[DCB_ATTR_IEEE_APP_TABLE], rem) {
+                       struct dcb_app *app_data;
+
+                       if (nla_type(attr) != DCB_ATTR_IEEE_APP)
+                               continue;
+                       app_data = nla_data(attr);
+                       if (ops->ieee_delapp)
+                               err = ops->ieee_delapp(netdev, app_data);
+                       else
+                               err = dcb_ieee_delapp(netdev, app_data);
+                       if (err)
+                               goto err;
+               }
+       }
+
+err:
+       dcbnl_reply(err, RTM_SETDCB, DCB_CMD_IEEE_DEL, DCB_ATTR_IEEE,
+                   pid, seq, flags);
+       dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_DEL, seq, 0);
+       return err;
+}
+
+
 /* DCBX configuration */
 static int dcbnl_getdcbx(struct net_device *netdev, struct nlattr **tb,
                         u32 pid, u32 seq, u16 flags)
@@ -1522,10 +1851,10 @@ err:
 static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
                         u32 pid, u32 seq, u16 flags)
 {
+       struct net *net = dev_net(netdev);
        struct sk_buff *skb;
        struct nlmsghdr *nlh;
        struct dcbmsg *dcb;
-       struct nlattr *cee;
        const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
        int err;
 
@@ -1536,51 +1865,26 @@ static int dcbnl_cee_get(struct net_device *netdev, struct nlattr **tb,
        if (!skb)
                return -ENOBUFS;
 
-       nlh = NLMSG_NEW(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+       nlh = nlmsg_put(skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+       if (nlh == NULL) {
+               nlmsg_free(skb);
+               return -EMSGSIZE;
+       }
 
        dcb = NLMSG_DATA(nlh);
        dcb->dcb_family = AF_UNSPEC;
        dcb->cmd = DCB_CMD_CEE_GET;
 
-       NLA_PUT_STRING(skb, DCB_ATTR_IFNAME, netdev->name);
+       err = dcbnl_cee_fill(skb, netdev);
 
-       cee = nla_nest_start(skb, DCB_ATTR_CEE);
-       if (!cee)
-               goto nla_put_failure;
-
-       /* get peer info if available */
-       if (ops->cee_peer_getpg) {
-               struct cee_pg pg;
-               err = ops->cee_peer_getpg(netdev, &pg);
-               if (!err)
-                       NLA_PUT(skb, DCB_ATTR_CEE_PEER_PG, sizeof(pg), &pg);
-       }
-
-       if (ops->cee_peer_getpfc) {
-               struct cee_pfc pfc;
-               err = ops->cee_peer_getpfc(netdev, &pfc);
-               if (!err)
-                       NLA_PUT(skb, DCB_ATTR_CEE_PEER_PFC, sizeof(pfc), &pfc);
-       }
-
-       if (ops->peer_getappinfo && ops->peer_getapptable) {
-               err = dcbnl_build_peer_app(netdev, skb,
-                                          DCB_ATTR_CEE_PEER_APP_TABLE,
-                                          DCB_ATTR_CEE_PEER_APP_INFO,
-                                          DCB_ATTR_CEE_PEER_APP);
-               if (err)
-                       goto nla_put_failure;
+       if (err < 0) {
+               nlmsg_cancel(skb, nlh);
+               nlmsg_free(skb);
+       } else {
+               nlmsg_end(skb, nlh);
+               err = rtnl_unicast(skb, net, pid);
        }
-
-       nla_nest_end(skb, cee);
-       nlmsg_end(skb, nlh);
-
-       return rtnl_unicast(skb, &init_net, pid);
-nla_put_failure:
-       nlmsg_cancel(skb, nlh);
-nlmsg_failure:
-       kfree_skb(skb);
-       return -1;
+       return err;
 }
 
 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
@@ -1690,11 +1994,15 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                goto out;
        case DCB_CMD_IEEE_SET:
                ret = dcbnl_ieee_set(netdev, tb, pid, nlh->nlmsg_seq,
-                                nlh->nlmsg_flags);
+                                    nlh->nlmsg_flags);
                goto out;
        case DCB_CMD_IEEE_GET:
                ret = dcbnl_ieee_get(netdev, tb, pid, nlh->nlmsg_seq,
-                                nlh->nlmsg_flags);
+                                    nlh->nlmsg_flags);
+               goto out;
+       case DCB_CMD_IEEE_DEL:
+               ret = dcbnl_ieee_del(netdev, tb, pid, nlh->nlmsg_seq,
+                                    nlh->nlmsg_flags);
                goto out;
        case DCB_CMD_GDCBX:
                ret = dcbnl_getdcbx(netdev, tb, pid, nlh->nlmsg_seq,
@@ -1754,12 +2062,13 @@ u8 dcb_getapp(struct net_device *dev, struct dcb_app *app)
 EXPORT_SYMBOL(dcb_getapp);
 
 /**
- * ixgbe_dcbnl_setapp - add dcb application data to app list
+ * dcb_setapp - add CEE dcb application data to app list
  *
- * Priority 0 is the default priority this removes applications
- * from the app list if the priority is set to zero.
+ * Priority 0 is an invalid priority in CEE spec. This routine
+ * removes applications from the app list if the priority is
+ * set to zero.
  */
-u8 dcb_setapp(struct net_device *dev, struct dcb_app *new)
+int dcb_setapp(struct net_device *dev, struct dcb_app *new)
 {
        struct dcb_app_type *itr;
        struct dcb_app_type event;
@@ -1802,6 +2111,114 @@ out:
 }
 EXPORT_SYMBOL(dcb_setapp);
 
+/**
+ * dcb_ieee_getapp_mask - retrieve the IEEE DCB application priority
+ *
+ * Helper routine which on success returns a non-zero 802.1Qaz user
+ * priority bitmap otherwise returns 0 to indicate the dcb_app was
+ * not found in APP list.
+ */
+u8 dcb_ieee_getapp_mask(struct net_device *dev, struct dcb_app *app)
+{
+       struct dcb_app_type *itr;
+       u8 prio = 0;
+
+       spin_lock(&dcb_lock);
+       list_for_each_entry(itr, &dcb_app_list, list) {
+               if (itr->app.selector == app->selector &&
+                   itr->app.protocol == app->protocol &&
+                   (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
+                       prio |= 1 << itr->app.priority;
+               }
+       }
+       spin_unlock(&dcb_lock);
+
+       return prio;
+}
+EXPORT_SYMBOL(dcb_ieee_getapp_mask);
+
+/**
+ * dcb_ieee_setapp - add IEEE dcb application data to app list
+ *
+ * This adds Application data to the list. Multiple application
+ * entries may exists for the same selector and protocol as long
+ * as the priorities are different.
+ */
+int dcb_ieee_setapp(struct net_device *dev, struct dcb_app *new)
+{
+       struct dcb_app_type *itr, *entry;
+       struct dcb_app_type event;
+       int err = 0;
+
+       memcpy(&event.name, dev->name, sizeof(event.name));
+       memcpy(&event.app, new, sizeof(event.app));
+
+       spin_lock(&dcb_lock);
+       /* Search for existing match and abort if found */
+       list_for_each_entry(itr, &dcb_app_list, list) {
+               if (itr->app.selector == new->selector &&
+                   itr->app.protocol == new->protocol &&
+                   itr->app.priority == new->priority &&
+                   (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
+                       err = -EEXIST;
+                       goto out;
+               }
+       }
+
+       /* App entry does not exist add new entry */
+       entry = kmalloc(sizeof(struct dcb_app_type), GFP_ATOMIC);
+       if (!entry) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       memcpy(&entry->app, new, sizeof(*new));
+       strncpy(entry->name, dev->name, IFNAMSIZ);
+       list_add(&entry->list, &dcb_app_list);
+out:
+       spin_unlock(&dcb_lock);
+       if (!err)
+               call_dcbevent_notifiers(DCB_APP_EVENT, &event);
+       return err;
+}
+EXPORT_SYMBOL(dcb_ieee_setapp);
+
+/**
+ * dcb_ieee_delapp - delete IEEE dcb application data from list
+ *
+ * This removes a matching APP data from the APP list
+ */
+int dcb_ieee_delapp(struct net_device *dev, struct dcb_app *del)
+{
+       struct dcb_app_type *itr;
+       struct dcb_app_type event;
+       int err = -ENOENT;
+
+       memcpy(&event.name, dev->name, sizeof(event.name));
+       memcpy(&event.app, del, sizeof(event.app));
+
+       spin_lock(&dcb_lock);
+       /* Search for existing match and remove it. */
+       list_for_each_entry(itr, &dcb_app_list, list) {
+               if (itr->app.selector == del->selector &&
+                   itr->app.protocol == del->protocol &&
+                   itr->app.priority == del->priority &&
+                   (strncmp(itr->name, dev->name, IFNAMSIZ) == 0)) {
+                       list_del(&itr->list);
+                       kfree(itr);
+                       err = 0;
+                       goto out;
+               }
+       }
+
+out:
+       spin_unlock(&dcb_lock);
+       if (!err)
+               call_dcbevent_notifiers(DCB_APP_EVENT, &event);
+       return err;
+}
+EXPORT_SYMBOL(dcb_ieee_delapp);
+
 static void dcb_flushapp(void)
 {
        struct dcb_app_type *app;