linux内核DCB子系统

网络设备是怎么利用linux内核的DCB子系统,来达到融合网络流量的各种各样的QoS需求的?融合网卡或者存储流量是否也可以使用到DCB子系统的,他们是怎样工作的?本文将对上面这两个问题进行解答;本文首先大体介绍了DCB机制和它的使用环境;然后介绍一个使用DCB的应用程序lldpad的例子;再然后介绍一个DCB子系统中重要的数据结构;最后介绍DCB内核模块和驱动的具体实现。

Overview

在整个DCB过程中,是要把各种各样的流量,可能是FCoE流量,可能是一般的TCP流量,还可能是其他的视频流量等等,他们对于QoS的要求各不相同,有的要求不丢包,。有的要求带宽保证等等,但是他们也许都需要从这一个网络接口发送到他们各自的目的地中去。由于意识到这个需求,在linux内核中,2.4?或者更早的版本中加入了TC(流量分类)模块,用来对不同的流量类型进行不同的处理。之前说到驱动模块是网络接口的agent,网络设备很可能也和内核一样,对于不同的流量类型也有不同的QoS处理,不过如果网络设备没有这个多队列和相关的处理,那么也不影响QoS的处理,只不过不能提速,在网卡这一块可能会成为瓶颈。使用了多个队列的网卡,在内部可能有一个处理器来进行这些复杂的多队列处理,然后驱动的DCB代码部分很可能需要完成TC映射的功能。但是如果说网卡没有多队列,内核的QoS任然可以发挥它的作用(当然要消耗CPU是必须的啦)。

驱动是网卡的agent,就相当于网卡是个聋哑人,主机是不能和网卡说话的,通过驱动,网卡和主机能够进行交互。主机说要从这接口发送包出去,于是调用驱动的发送函数,把包发送出去。如果网卡物理层收到包,则通过驱动的中断函数来处理这些包(为了提高效率,现在也有可能使用到NAPI)。本来发送和接受都好说,当然是用最快的速度处理发包和收包就好。但是当流量类型渐渐复杂的时候,就要针对不同的流量进行不同的处理。比如说我们的主机上有飞机,坦克,自行车,当都必须经过这个接口出去时,我们按照飞机的优先级最高,自行车优先级最低,只有当飞机和坦克都过去了之后,自行车才能够通行(我们的主机内存很多,给飞机一个队,坦克一个队,自行车一个队)。如果这个接口很宽,我们还可以把这个接口设置几个队列,要出去的直接在接口上拍队(当然也是先通过内存的平滑缓冲)。道路上认为一次只能通过一个东西。

用户的流量特征我们可以通过lldpad设置,设置了这个值,而且设置的而这些信息是要和对端交换机进行交互的,于是通过那个接口发出去,设置的这个值是要和内核交互的,当内核协议栈收到这些信息的时候,需要配置相应的队列和算法(同时还要获取硬件信息,如果有必要还要把tc队列映射到网卡队列),和驱动交互的另外一个原因很可能是因为dcb-lldp需要使用驱动本身要传递的网卡DCB信息和要求。

关于存储流量,比如FCoE流量,是不会经过内核的Qdisc的,他经过的是FcoE模块,在FCoE模块中也是会使用DCB模块的额,从而达到和Qdisc一样的目的?

Q.FCoE模块为何也要用到dcb模块中的函数?

A.FCoE模块作为FCoE协议的处理模块,需要配置相应的FCoE类型和DCB类型的包的DCB参数。(这是不是假如它不再经过802.1p网络层次?)

Q.发挥了什么作用?

A.获取了FCoE和FIP类型的的优先级

Up(FCoE优先级);Fup(FIP优先级)


static void fcoe_dcb_create(struct fcoe_interface *fcoe)

{

#ifdef CONFIG_DCB

int dcbx;

u8 fup, up;

struct net_device *netdev = fcoe->realdev;

struct fcoe_port *port = lport_priv(fcoe->ctlr.lp);

struct dcb_app app = {

.priority = 0,

.protocol = ETH_P_FCOE

};

...

app.selector = DCB_APP_IDTYPE_ETHTYPE;

up = dcb_getapp(netdev, &app);

app.protocol = ETH_P_FIP;

fup = dcb_getapp(netdev, &app);

}

port->priority = ffs(up) ? ffs(up) - 1 : 0;

fcoe->ctlr.priority = ffs(fup) ? ffs(fup) - 1 : port->priority;

除了DCB初始化函数,fcoe_dcb_create;内核提供了DCB,NET和CPU通知链注册/注销和工作队列的接口函数。

LLDPAD

这个应用程序是用来配置Intel网络设备的DCB特性的。

Listed below are the applicablestandards:

Enhanced Transmission Selection: IEEE 802.1Qaz

Lossless Traffic Class

Priority Flow Control: IEEE 802.1Qbb

Congestion Notification: IEEE 802.1Qau

DCB Capability exchange protocol (DCBX): IEEE 802.1Qaz

那么怎么使用lldpad配置DCB特性呢?比如使用用户接口lldpad。

Dcbtool

Dcbtool可以用来查询和设置DCB以太网接口的DCB特性。通用的命令有gc, sc等。(对应的DCB模块的get和set函数),主要可以参考https://github.com/jrfastab/lldpad
比如:<gc|go> dcbx:gets the configured or operational version of the  DCB  capabilities  exchange  protocol.  
可以设置本地interface的配置特性。
sc <ifname> <feature> <args>
              sets the configuration of feature on interface ifname.
这些特性feature包括:
        dcb    DCB state of the port
 
       pg     priority groups
pgid:xxxxxxxx
Priority group ID for the 8  priorities.   From  left  to  right
(priorities  0-7),  x  is  the  corresponding  priority group ID
value, which can be 0-7 for priority groups with bandwidth allo-
cations  or f (priority group ID 15) for the unrestricted prior-
ity group.
 
 
       pfc    priority flow control(特殊的参数有pfcup: xxxxxxxx
)x是0或1,1指的是这个相应的优先级(总共有8个优先级0-7嘛)使用传输的pause帧机制,0就表示不使用。
 
       app:<subtype> 特殊的参数是appcfg:xx xx是一个16进制的值代表一个8bit的bitmap,某一位为1代表着这个subtype使用这个优先级。
 
              application specific data
       subtype can be:
       ---------------
       0|fcoe Fiber Channel over Ethernet (FCoE)
      
下面是dcbtool的使用例子:
达到的目的:使得PFC pause发生作用的传输优先级是3,并且将FCoE流量分配到这个第三优先级上。
       dcbtool sc eth2 pfc pfcup:00010000
       dcbtool sc eth2 app:0 appcfg:08
(app:0是表示FcoE流量)

另外带宽分配的部分就是pg:比如
       dcbtool sc eth2 pg pgid:0000111f pgpct:25,75,0,0,0,0,0,0


使用Netlink和内核DCB子系统交互

在net\netlink\af_netlink.c中:


static int __init netlink_proto_init(void)

sock_register(&netlink_family_ops);

}

static const struct net_proto_familynetlink_family_ops = {

       .family = PF_NETLINK,

       .create = netlink_create,

       .owner    = THIS_MODULE, /* for consistency 8) */

};

 


在netlink_create中调用

static int __netlink_create(struct net *net, struct socket *sock,

                         struct mutex *cb_mutex, int protocol)

{

       struct sock *sk;

       struct netlink_sock *nlk;

 

       sock->ops = &netlink_ops;

       sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto);

      

       …

}

 

static const struct proto_opsnetlink_ops= {

       .family = PF_NETLINK,

       .owner = THIS_MODULE,

       .release =      netlink_release,

       .bind =          netlink_bind,

       .connect =     netlink_connect,

       .socketpair = sock_no_socketpair,

       .accept =       sock_no_accept,

       .getname =    netlink_getname,

       .poll =           datagram_poll,

       .ioctl =   sock_no_ioctl,

       .listen =  sock_no_listen,

       .shutdown =  sock_no_shutdown,

       .setsockopt =       netlink_setsockopt,

       .getsockopt =       netlink_getsockopt,

       .sendmsg =   netlink_sendmsg,//这可能就是和那些系统调用对应的函数

       .recvmsg =    netlink_recvmsg,

       .mmap =              sock_no_mmap,

       .sendpage =  sock_no_sendpage,

};

 

 

使用Netlink和内核DCB子系统交互

在net\netlink\af_netlink.c中:


static int __init netlink_proto_init(void)

sock_register(&netlink_family_ops);

}

static const struct net_proto_familynetlink_family_ops = {

       .family = PF_NETLINK,

       .create = netlink_create,

       .owner    = THIS_MODULE, /* for consistency 8) */

};

 


在netlink_create中调用

static int __netlink_create(struct net *net, struct socket *sock,

                         struct mutex *cb_mutex, int protocol)

{

       struct sock *sk;

       struct netlink_sock *nlk;

 

       sock->ops = &netlink_ops;

       sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto);

      

       …

}

 

static const struct proto_opsnetlink_ops= {

       .family = PF_NETLINK,

       .owner = THIS_MODULE,

       .release =      netlink_release,

       .bind =          netlink_bind,

       .connect =     netlink_connect,

       .socketpair = sock_no_socketpair,

       .accept =       sock_no_accept,

       .getname =    netlink_getname,

       .poll =           datagram_poll,

       .ioctl =   sock_no_ioctl,

       .listen =  sock_no_listen,

       .shutdown =  sock_no_shutdown,

       .setsockopt =       netlink_setsockopt,

       .getsockopt =       netlink_getsockopt,

       .sendmsg =   netlink_sendmsg,//这可能就是和那些系统调用对应的函数

       .recvmsg =    netlink_recvmsg,

       .mmap =              sock_no_mmap,

       .sendpage =  sock_no_sendpage,

};

 

 

数据结构dcbnl_ops

这里的dcbnl_ops应该算是routing子系统中的一个需要用到的结构。
为了进一步理解,还是把这个过程弄清楚吧。
 
 
到现在lldpad怎么操作,基本上梳理清楚,至于lldpad怎么和内核程序进行交互。应该要看一看struct dcbnl_rtnl_ops出现在内核的哪些部分。

include/net/dcbnl.h定义这个结构

·         *
·          43  * Ops struct for the netlink callbacks.  Used by DCB-enabled drivers through* the netdevice struct.
·          45  */
·          46 struct dcbnl_rtnl_ops {
·          47         /* IEEE 802.1Qaz std */
·56         int (*ieee_delapp) (struct net_device *, struct dcb_app *);
·59
·          60         /* CEE std */
·          61         u8   (*getstate)(struct net_device *);
·                         u16 *);
·          96         int (*peer_getapptable)(struct net_device *, struct dcb_app *);
·          97 
·          98         /* CEE peer */
·          99         int (*cee_peer_getpg) (struct net_device *, struct cee_pg *);
·100         int (*cee_peer_getpfc) (struct net_device *, struct cee_pfc *);
·101 };
·102
·103 #endif /* __NET_DCBNL_H__ */
·104

referenced in by驱动(DCB enabled)和DCB模块

然后referenced in很多的地方:
被很多的驱动引用,比如broadcom的bnx2x(这个编译内核的时候没有必要选上吧)。mellanox/mlx4;/qlogic/qlcnic;intel/ixgbe;等
这些基本上都是定义并且实现了这个结构;并且把这个结构作为netdev的子结构传递给netdev结构体。
 
然后在net/dcb/dcbnl.c(DCB模块)中有这些函数
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)
然后这个里面使用了一个变量指针ops,将这个netdev的dcbnl_ops传递给它。
const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
 
static int dcbnl_ieee_fill(struct sk_buff *skb, struct net_device *netdev)
1035 {
1036         struct nlattr *ieee, *app;
1037         struct dcb_app_type *itr;
1038         const struct dcbnl_rtnl_ops *ops = netdev->dcbnl_ops;
1039         int dcbx;
 
static int dcbnl_cee_pg_fill(struct sk_buff *skb, struct net_device *dev,
1142                              int dir)
1143 {
1144         u8pgid, up_map, prio, tc_pct;
1145         const struct dcbnl_rtnl_ops *ops = dev->dcbnl_ops;
 
还有dcbnl_notify
dcbnl_cee_fill(
dcbnl_cee_get/* Handle CEE DCBX GET commands. */

DCB模块

Net/dcb目录

主要是和应用程序交互,解析应用程序的包,执行相关的功能,然后去调用变量的callback函数进行get或者set操作,再将结果反馈给应用程序lldpad。

DCB子系统注册rtnetlink

感觉看一下这个3.2的代码完全没有什么问题的呀。差不多就是那个论文中提到的那样子

Note:翻译自代码,可是翻译起来真的好带感呢。

__rtnl_register函数:注册一个rtnetlink消息类型(是提供给模块自己注册的哦)

参数

@protocol:协议家族或者PF_UNSPEC

@msgtype:rtnetlink的消息类型

@doit:每次请求消息调用的函数指针

@dumpit:每次dump请求NLM_F_DUM调用的函数指针

@calit:计算dump消息大小的指针函数

 

static struct rtnl_link*rtnl_msg_handlers[RTNL_FAMILY_MAX + 1];

 

int __rtnl_register(int protocol, intmsgtype,

                  rtnl_doit_func doit, rtnl_dumpit_funcdumpit,

                  rtnl_calcit_func calcit){

struct rtnl_link *tab;

       intmsgindex;

 

       BUG_ON(protocol< 0 || protocol > RTNL_FAMILY_MAX);

       msgindex= rtm_msgindex(msgtype);

 

       tab= rtnl_msg_handlers[protocol];

       if(tab == NULL) {

              tab= kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL);

              if(tab == NULL)

                     return-ENOBUFS;

 

              rtnl_msg_handlers[protocol]= tab;

       }

 

       if(doit)

              tab[msgindex].doit= doit;

 

       if(dumpit)

              tab[msgindex].dumpit= dumpit;

 

       if(calcit)

              tab[msgindex].calcit= calcit;

 

       return0;

}

EXPORT_SYMBOL_GPL(__rtnl_register);

void rtnl_register(int protocol, intmsgtype,

                 rtnl_doit_func doit, rtnl_dumpit_funcdumpit,

                 rtnl_calcit_func calcit)

{

       if(__rtnl_register(protocol, msgtype, doit, dumpit, calcit) < 0)

              panic("Unableto register rtnetlink message handler, "

                    "protocol = %d, message type =%d\n",

                    protocol, msgtype);

}

EXPORT_SYMBOL_GPL(rtnl_register);

当消息到达doit之后:

Dcb/dcbnl.c中的

static int __init dcbnl_init(void)

{

       INIT_LIST_HEAD(&dcb_app_list);

 

       rtnl_register(PF_UNSPEC,RTM_GETDCB, dcb_doit, NULL, NULL);

       rtnl_register(PF_UNSPEC,RTM_SETDCB, dcb_doit, NULL, NULL);

 

       return0;

}

然后这个dcb_doit做了很多的事情,比如说解析skb和其他头部,然后进行相关的操作。

static int dcb_doit(struct sk_buff *skb,structnlmsghdr *nlh, void *arg)

{

       structnet *net = sock_net(skb->sk);

       structnet_device *netdev;

       structdcbmsg  *dcb = (struct dcbmsg *)NLMSG_DATA(nlh);

       structnlattr *tb[DCB_ATTR_MAX + 1];

       u32pid = skb ? NETLINK_CB(skb).pid : 0;

       intret = -EINVAL;

 

       if(!net_eq(net, &init_net))

              return-EINVAL;

 

       ret= nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX,

                       dcbnl_rtnl_policy);

       if(ret < 0)

              returnret;

 

       if(!tb[DCB_ATTR_IFNAME])

              return-EINVAL;

 

       netdev= dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME]));

       if(!netdev)

              return-EINVAL;

 

       if(!netdev->dcbnl_ops)

              gotoerrout;

 

       switch(dcb->cmd) {

       caseDCB_CMD_GSTATE:

              ret= dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq,

                                   nlh->nlmsg_flags);


/**

* enum dcbnl_attrs - DCB top-level netlink attributes

*

* @DCB_ATTR_UNDEFINED: unspecified attribute to catch errors

* @DCB_ATTR_IFNAME: interface name of the underlying device (NLA_STRING)

* @DCB_ATTR_STATE: enable state of DCB in the device (NLA_U8)

* @DCB_ATTR_PFC_STATE: enable state of PFC in the device (NLA_U8)

* @DCB_ATTR_PFC_CFG: priority flow control configuration (NLA_NESTED)

* @DCB_ATTR_NUM_TC: number of traffic classes supported in the device (NLA_U8)

* @DCB_ATTR_PG_CFG: priority group configuration (NLA_NESTED)

* @DCB_ATTR_SET_ALL: bool to commit changes to hardware or not (NLA_U8)

* @DCB_ATTR_PERM_HWADDR: MAC address of the physical device (NLA_NESTED)

* @DCB_ATTR_CAP: DCB capabilities of the device (NLA_NESTED)

* @DCB_ATTR_NUMTCS: number of traffic classes supported (NLA_NESTED)

* @DCB_ATTR_BCN: backward congestion notification configuration (NLA_NESTED)

* @DCB_ATTR_IEEE: IEEE 802.1Qaz supported attributes (NLA_NESTED)

* @DCB_ATTR_DCBX: DCBX engine configuration in the device (NLA_U8)

* @DCB_ATTR_FEATCFG: DCBX features flags (NLA_NESTED)

* @DCB_ATTR_CEE: CEE std supported attributes (NLA_NESTED)

*/

 


struct nlattr {

__u16           nla_len;

__u16           nla_type;

};


struct nlmsghdr {

__u32                nlmsg_len;       /* Length of message including header */

__u16                nlmsg_type;     /* Message content */

__u16                nlmsg_flags;    /* Additional flags */

__u32                nlmsg_seq;      /* Sequence number */

__u32                nlmsg_pid;       /* Sending process port ID */

};

 

自定义的一些DCB属性,比如:


/* DCB netlink attributes policy */

static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {

[DCB_ATTR_IFNAME]      = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},

[DCB_ATTR_STATE]       = {.type = NLA_U8},

[DCB_ATTR_PFC_CFG]     = {.type = NLA_NESTED},

[DCB_ATTR_PG_CFG]      = {.type = NLA_NESTED},

[DCB_ATTR_SET_ALL]     = {.type = NLA_U8},

[DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG},

[DCB_ATTR_CAP]         = {.type = NLA_NESTED},

[DCB_ATTR_PFC_STATE]   = {.type = NLA_U8},

[DCB_ATTR_BCN]         = {.type = NLA_NESTED},

[DCB_ATTR_APP]         = {.type = NLA_NESTED},

[DCB_ATTR_IEEE]           = {.type = NLA_NESTED},

[DCB_ATTR_DCBX]        = {.type = NLA_U8},

[DCB_ATTR_FEATCFG]     = {.type = NLA_NESTED},

};

 

关于rtmsg的解析,是这样实现的


/**

 * nlmsg_parse - parse attributes of a netlink message

 * @nlh: netlink message header

 * @hdrlen: length of family specific header

 * @tb: destination array with maxtype+1 elements

 * @maxtype: maximum attribute type to be expected

 * @policy: validation policy

 *

 * See nla_parse()

 */

static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,

                           struct nlattr *tb[], int maxtype,

                           const struct nla_policy *policy)

{

       if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))

              return -EINVAL;

 

       return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),

                      nlmsg_attrlen(nlh, hdrlen), policy);

}

Parses a stream of attributes and stores a pointer to each attribute in

 * the tb array accessible via the attribute type. Attributes with a type

 * exceeding maxtype will be silently ignored for backwards compatibility

 * reasons. policy may be set to NULL if no validation is required.

 *

 * Returns 0 on success or a negative error code.

 */

int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,

             int len, const struct nla_policy *policy)

{

       const struct nlattr *nla;

       int rem, err;

 

       memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));

 

       nla_for_each_attr(nla, head, len, rem) {

              u16 type = nla_type(nla);

 

              if (type > 0 && type <= maxtype) {

                     if (policy) {

                            err = validate_nla(nla, maxtype, policy);

                            if (err < 0)

                                   goto errout;

                     }

 

                     tb[type] = (struct nlattr *)nla;

              }

       }

 

 

 

关于dcbmsg结构是在dcbnl.h中定义的


struct dcbmsg {

       __u8               dcb_family;

       __u8               cmd;

       __u16              dcb_pad;

};

命令包括:

/**

 * enum dcbnl_commands - supported DCB commands

 *

 * @DCB_CMD_UNDEFINED: unspecified command to catch errors

 * @DCB_CMD_GSTATE: request the state of DCB in the device

 * @DCB_CMD_SSTATE: set the state of DCB in the device

 * @DCB_CMD_PGTX_GCFG: request the priority group configuration for Tx

 * @DCB_CMD_PGTX_SCFG: set the priority group configuration for Tx

 * @DCB_CMD_PGRX_GCFG: request the priority group configuration for Rx

 * @DCB_CMD_PGRX_SCFG: set the priority group configuration for Rx

 * @DCB_CMD_PFC_GCFG: request the priority flow control configuration

 * @DCB_CMD_PFC_SCFG: set the priority flow control configuration

 * @DCB_CMD_SET_ALL: apply all changes to the underlying device

 * @DCB_CMD_GPERM_HWADDR: get the permanent MAC address of the underlying

 *                        device.  Only useful when using bonding.

 * @DCB_CMD_GCAP: request the DCB capabilities of the device

 * @DCB_CMD_GNUMTCS: get the number of traffic classes currently supported

 * @DCB_CMD_SNUMTCS: set the number of traffic classes

 * @DCB_CMD_GBCN: set backward congestion notification configuration

 * @DCB_CMD_SBCN: get backward congestion notification configration.

 * @DCB_CMD_GAPP: get application protocol configuration

 * @DCB_CMD_SAPP: set application protocol configuration

 * @DCB_CMD_IEEE_SET: set IEEE 802.1Qaz configuration

 * @DCB_CMD_IEEE_GET: get IEEE 802.1Qaz configuration

 * @DCB_CMD_GDCBX: get DCBX engine configuration

 * @DCB_CMD_SDCBX: set DCBX engine configuration

 * @DCB_CMD_GFEATCFG: get DCBX features flags

 * @DCB_CMD_SFEATCFG: set DCBX features negotiation flags

 * @DCB_CMD_CEE_GET: get CEE aggregated configuration

 * @DCB_CMD_IEEE_DEL: delete IEEE 802.1Qaz configuration

 */

 

一个标准的netlink replay call的例子如下,比如get的时候就是基本上调用了它。


static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid,

u32 seq, u16 flags)

{

struct sk_buff *dcbnl_skb;

struct dcbmsg *dcb;

struct nlmsghdr *nlh;

int ret = -EINVAL

dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);

if (!dcbnl_skb)

return ret;

nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags);

dcb = NLMSG_DATA(nlh);

dcb->dcb_family = AF_UNSPEC;

dcb->cmd = cmd;

dcb->dcb_pad = 0;

ret = nla_put_u8(dcbnl_skb, attr, value);

if (ret)

goto err;

/* end the message, assign the nlmsg_len. */

nlmsg_end(dcbnl_skb, nlh);

ret = rtnl_unicast(dcbnl_skb, &init_net, pid);

驱动定义dcbnl_ops

驱动:比如82599的驱动Ixgbe,或者netfpga的驱动都可以根据自己的需要来定义这个结构dcbnl_ops中的函数指针。Dcbnl_ops就是实现了很多的函数体,这些函数体都要驱动的dcb.c(差不多类似的名字)中实现。这个在netfpga的时候,主要是要和lldpad进行交互,82555可能设置了硬件的DCB配置,可是netfpga的硬件并没有这个功能。不过DCB模块也会和FCoE模块进行交互,好像调用的就是DCB模块中的函数(⊙▽⊙不知道这些函数还有没有调用那个变量的函数,如果调用了,才有意思呢。!关于丽丽总是在问的app
优先级。。还是要结合lldpad一起看会比较好吧。其实我倒是不在乎这个)。

setall应该是重置

get/set pfc tcnum app等。

82599的硬件初始化

这些硬件的配置利用的结构是adapter->dcb_cfg(与硬件相关的结构体),这个是网卡的默认DCB配置。

参考文献

lldpad的readme
lldpad源码
ixgbe源码
时间: 2024-10-14 04:18:54

linux内核DCB子系统的相关文章

Linux 内核无线子系统

Linux 内核无线子系统 浅谈 Linux 内核无线子系统 Table of Contents 1. 全局概览 2. 模块间接口 3. 数据路径与管理路径 4. 数据包是如何被发送? 5. 谈谈管理路径 6. 数据包又是如何被接收? 7. 总结一下 Linux 内核是如何实现无线网络接口呢?数据包是通过怎样的方式被发送和接收呢?刚开始工作接触 Linux 无线网络时,我曾迷失在浩瀚的基础代码中,寻找具有介绍性的材料来回答如上面提到的那些高层次的问题.跟踪探索了一段时间的源代码后,我写下了这篇总

(转)浅谈 Linux 内核无线子系统

前言 Linux 内核是如何实现无线网络接口呢?数据包是通过怎样的方式被发送和接收呢? 刚开始工作接触 Linux 无线网络时,我曾迷失在浩瀚的基础代码中,寻找具有介绍性的材料来回答如上面提到的那些高层次的问题. 跟踪探索了一段时间的源代码后,我写下了这篇总结,希望在 Linux 无线网络的工作原理上,读者能从这篇文章获得一个具有帮助性的概览. 1.全局概览 在开始探索 Linux 无线具体细节之前,让我们先来把握一下 Linux 无线子系统整体结构.如图1,展示了 Linux 无线子系统各个模

linux内核I2C子系统学习(三)

写设备驱动: 四部曲: 构建i2c_driver 注册i2c_driver 构建i2c_client ( 第一种方法:注册字符设备驱动.第二种方法:通过板文件的i2c_board_info填充,然后注册) 注销i2c_driver 具体如下: ●    构建i2c_driver static struct i2c_driver pca953x_driver = {                 .driver = {                                     .n

Linux内核(11) - 子系统的初始化之内核选项解析

首先感谢国家.其次感谢上大的钟莉颖,让我知道了大学不仅有校花,还有校鸡,而且很多时候这两者其实没什么差别.最后感谢清华女刘静,让我深刻体会到了素质教育的重要性,让我感到有责任写写子系统的初始化. 各个子系统的初始化是内核整个初始化过程必然要完成的基本任务,这些任务按照固定的模式来处理,可以归纳为两个部分:内核选项的解析以及那些子系统入口(初始化)函数的调用. 内核选项 Linux允许用户传递内核配置选项给内核,内核在初始化过程中调用parse_args函数对这些选项进行解析,并调用相应的处理函数

Linux内核(12) - 子系统的初始化之那些入口函数

内核选项的解析完成之后,各个子系统的初始化即进入第二部分-入口函数的调用.通常USB.PCI这样的子系统都会有一个名为subsys_initcall的入口,如果你选择它们作为研究内核的切入点,那么就请首先找到它. 朱德庸在<关于上班这件事>里说,要花前半生找入口,花后半生找出口.可见寻找入口对于咱们这一生,对于看内核代码这件事儿都是无比重要的. 但是很多时候,入口并不仅仅只有subsys_initcall一个,比如PCI. 117 #define pure_initcall(fn)      

Linux内核(13) - 子系统的初始化之以PCI子系统为例

由Kconfig这张地图的分布来看,PCI这块儿的代码应该分布在两个地方,drivers/pci和arch/i386/pci,两岸三地都属于一个中国,不管是drivers/pci那儿的,还是arch/i386/pci那儿的,也都只属于一个PCI子系统,本着一个中国的原则,咱们要统筹的全面的考察分析位于两个地方的代码,于是,这些远远突破了五位数的代码左看右看横看竖看都显得那么的阴森恐怖,不过人家咋说也是整个一PCI子系统,就像走在T台上的芙蓉姐姐和杨二车那姆一样,看起来恐怖但也是很有内涵的,岂能够

嵌入式Linux内核I2C子系统详解

1.1 I2C总线知识 1.1.1  I2C总线物理拓扑结构     I2C总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成.通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递.在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平. 1.1.2  I2C总线特征    I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址(可以从I2C器件的数据手册得知),主

Linux内核简介、子系统及分类

一.内核简介 内核:在计算机科学中是一个用来管理软件发出的数据I/O(输入与输出)要求的计算机程序,将这些要求转译为数据处理的指令并交由中央处理器(CPU)及计算机中其他电子组件进行处理,是现代操作系统中最基本的部分.它是为众多应用程序提供对计算机硬件的安全访问的一部分软件,这种访问是有限的,并由内核决定一个程序在什么时候对某部分硬件操作多长时间.直接对硬件操作是非常复杂的.所以内核通常提供一种硬件抽象的方法,来完成这些操作.通过进程间通信机制及系统调用,应用进程可间接控制所需的硬件资源(特别是

Linux内核分析(五)----字符设备驱动实现

原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷,我们都会以虚拟的设备为例进行学习,所以大家不必害怕没有硬件的问题. 今天我们会分析到以下内容: 1.      字符设备驱动基础 2.      简单字符设备驱动实现 3.      驱动测试 l  字符设备基础 1.       字符设备描述结构 在linux2.6内核中,使用cdev结构体描述一