struct mutex reporters_lock; /* Protects reporter_list */
 };
 
+struct devlink_port_new_attrs {
+       enum devlink_port_flavour flavour;
+       unsigned int port_index;
+       u32 controller;
+       u32 sfnum;
+       u16 pfnum;
+       u8 port_index_valid:1,
+          controller_valid:1,
+          sfnum_valid:1;
+};
+
 struct devlink_sb_pool_info {
        enum devlink_sb_pool_type pool_type;
        u32 size;
        int (*port_function_hw_addr_set)(struct devlink *devlink, struct devlink_port *port,
                                         const u8 *hw_addr, int hw_addr_len,
                                         struct netlink_ext_ack *extack);
+       /**
+        * port_new() - Add a new port function of a specified flavor
+        * @devlink: Devlink instance
+        * @attrs: attributes of the new port
+        * @extack: extack for reporting error messages
+        * @new_port_index: index of the new port
+        *
+        * Devlink core will call this device driver function upon user request
+        * to create a new port function of a specified flavor and optional
+        * attributes
+        *
+        * Notes:
+        *      - Called without devlink instance lock being held. Drivers must
+        *        implement own means of synchronization
+        *      - On success, drivers must register a port with devlink core
+        *
+        * Return: 0 on success, negative value otherwise.
+        */
+       int (*port_new)(struct devlink *devlink,
+                       const struct devlink_port_new_attrs *attrs,
+                       struct netlink_ext_ack *extack,
+                       unsigned int *new_port_index);
+       /**
+        * port_del() - Delete a port function
+        * @devlink: Devlink instance
+        * @port_index: port function index to delete
+        * @extack: extack for reporting error messages
+        *
+        * Devlink core will call this device driver function upon user request
+        * to delete a previously created port function
+        *
+        * Notes:
+        *      - Called without devlink instance lock being held. Drivers must
+        *        implement own means of synchronization
+        *      - On success, drivers must unregister the corresponding devlink
+        *        port
+        *
+        * Return: 0 on success, negative value otherwise.
+        */
+       int (*port_del)(struct devlink *devlink, unsigned int port_index,
+                       struct netlink_ext_ack *extack);
 };
 
 static inline void *devlink_priv(struct devlink *devlink)
 
        return devlink_port_unsplit(devlink, port_index, info->extack);
 }
 
+static int devlink_port_new_notifiy(struct devlink *devlink,
+                                   unsigned int port_index,
+                                   struct genl_info *info)
+{
+       struct devlink_port *devlink_port;
+       struct sk_buff *msg;
+       int err;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       mutex_lock(&devlink->lock);
+       devlink_port = devlink_port_get_by_index(devlink, port_index);
+       if (!devlink_port) {
+               err = -ENODEV;
+               goto out;
+       }
+
+       err = devlink_nl_port_fill(msg, devlink, devlink_port,
+                                  DEVLINK_CMD_NEW, info->snd_portid,
+                                  info->snd_seq, 0, NULL);
+       if (err)
+               goto out;
+
+       err = genlmsg_reply(msg, info);
+       mutex_unlock(&devlink->lock);
+       return err;
+
+out:
+       mutex_unlock(&devlink->lock);
+       nlmsg_free(msg);
+       return err;
+}
+
+static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb,
+                                       struct genl_info *info)
+{
+       struct netlink_ext_ack *extack = info->extack;
+       struct devlink_port_new_attrs new_attrs = {};
+       struct devlink *devlink = info->user_ptr[0];
+       unsigned int new_port_index;
+       int err;
+
+       if (!devlink->ops->port_new || !devlink->ops->port_del)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[DEVLINK_ATTR_PORT_FLAVOUR] ||
+           !info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
+               NL_SET_ERR_MSG_MOD(extack, "Port flavour or PCI PF are not specified");
+               return -EINVAL;
+       }
+       new_attrs.flavour = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_FLAVOUR]);
+       new_attrs.pfnum =
+               nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
+
+       if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
+               /* Port index of the new port being created by driver. */
+               new_attrs.port_index =
+                       nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
+               new_attrs.port_index_valid = true;
+       }
+       if (info->attrs[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]) {
+               new_attrs.controller =
+                       nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]);
+               new_attrs.controller_valid = true;
+       }
+       if (new_attrs.flavour == DEVLINK_PORT_FLAVOUR_PCI_SF &&
+           info->attrs[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]) {
+               new_attrs.sfnum = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]);
+               new_attrs.sfnum_valid = true;
+       }
+
+       err = devlink->ops->port_new(devlink, &new_attrs, extack,
+                                    &new_port_index);
+       if (err)
+               return err;
+
+       err = devlink_port_new_notifiy(devlink, new_port_index, info);
+       if (err && err != -ENODEV) {
+               /* Fail to send the response; destroy newly created port. */
+               devlink->ops->port_del(devlink, new_port_index, extack);
+       }
+       return err;
+}
+
+static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb,
+                                       struct genl_info *info)
+{
+       struct netlink_ext_ack *extack = info->extack;
+       struct devlink *devlink = info->user_ptr[0];
+       unsigned int port_index;
+
+       if (!devlink->ops->port_del)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
+               NL_SET_ERR_MSG_MOD(extack, "Port index is not specified");
+               return -EINVAL;
+       }
+       port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
+
+       return devlink->ops->port_del(devlink, port_index, extack);
+}
+
 static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
                              struct devlink_sb *devlink_sb,
                              enum devlink_command cmd, u32 portid,
        [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
                                                        DEVLINK_RELOAD_ACTION_MAX),
        [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK),
+       [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 },
+       [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 },
+       [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 },
+       [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 },
 };
 
 static const struct genl_small_ops devlink_nl_ops[] = {
                .flags = GENL_ADMIN_PERM,
                .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
        },
+       {
+               .cmd = DEVLINK_CMD_PORT_NEW,
+               .doit = devlink_nl_cmd_port_new_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_DEL,
+               .doit = devlink_nl_cmd_port_del_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
+       },
        {
                .cmd = DEVLINK_CMD_SB_GET,
                .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,