본문 바로가기
프로그램.../프로....Kernel

[Netlink] kernel-space sample (Using Generic Netlink sockets)

by 크크다스 2014. 11. 14.
반응형

http://www.linuxfoundation.org/collaborate/workgroups/networking/generic_netlink_howto

http://www.carisma.slowglass.com/~tgr/libnl/


= 펌> use Netlink Protocol Library Suite (libnl).

Generic Netlink sockets - example code

linux/kernels/mips-linux-2.6.15/include/net/netlink.h


/* ========================================================================
 *         Netlink Messages and Attributes Interface (As Seen On TV)
 * ------------------------------------------------------------------------
 *                          Messages Interface
 * ------------------------------------------------------------------------
 *
 * Message Format:
 *    <--- nlmsg_total_size(payload)  --->
 *    <-- nlmsg_msg_size(payload) ->
 *   +----------+- - -+-------------+- - -+-------- - -
 *   | nlmsghdr | Pad |   Payload   | Pad | nlmsghdr
 *   +----------+- - -+-------------+- - -+-------- - -
 *   nlmsg_data(nlh)---^                   ^
 *   nlmsg_next(nlh)-----------------------+
 *
 * Payload Format:
 *    <---------------------- nlmsg_len(nlh) --------------------->
 *    <------ hdrlen ------>       <- nlmsg_attrlen(nlh, hdrlen) ->
 *   +----------------------+- - -+--------------------------------+
 *   |     Family Header    | Pad |           Attributes           |
 *   +----------------------+- - -+--------------------------------+
 *   nlmsg_attrdata(nlh, hdrlen)---^
 *
 * Data Structures:
 *   struct nlmsghdr            netlink message header
 *
 * Message Construction:
 *   nlmsg_new()            create a new netlink message
 *   nlmsg_put()            add a netlink message to an skb
 *   nlmsg_put_answer()            callback based nlmsg_put()
 *   nlmsg_end()            finanlize netlink message
 *   nlmsg_cancel()            cancel message construction
 *   nlmsg_free()            free a netlink message
 *
 * Message Sending:
 *   nlmsg_multicast()            multicast message to several groups
 *   nlmsg_unicast()            unicast a message to a single socket
 *
 * Message Length Calculations:
 *   nlmsg_msg_size(payload)        length of message w/o padding
 *   nlmsg_total_size(payload)        length of message w/ padding
 *   nlmsg_padlen(payload)        length of padding at tail
 *
 * Message Payload Access:
 *   nlmsg_data(nlh)            head of message payload
 *   nlmsg_len(nlh)            length of message payload
 *   nlmsg_attrdata(nlh, hdrlen)    head of attributes data
 *   nlmsg_attrlen(nlh, hdrlen)        length of attributes data
 *
 * Message Parsing:
 *   nlmsg_ok(nlh, remaining)        does nlh fit into remaining bytes?
 *   nlmsg_next(nlh, remaining)        get next netlink message
 *   nlmsg_parse()            parse attributes of a message
 *   nlmsg_find_attr()            find an attribute in a message
 *   nlmsg_for_each_msg()        loop over all messages
 *   nlmsg_validate()            validate netlink message incl. attrs
 *   nlmsg_for_each_attr()        loop over all attributes
 *
 * ------------------------------------------------------------------------
 *                          Attributes Interface
 * ------------------------------------------------------------------------
 *
 * Attribute Format:
 *    <------- nla_total_size(payload) ------->
 *    <---- nla_attr_size(payload) ----->
 *   +----------+- - -+- - - - - - - - - +- - -+-------- - -
 *   |  Header  | Pad |     Payload      | Pad |  Header
 *   +----------+- - -+- - - - - - - - - +- - -+-------- - -
 *                     <- nla_len(nla) ->      ^
 *   nla_data(nla)----^                        |
 *   nla_next(nla)-----------------------------'
 *
 * Data Structures:
 *   struct nlattr            netlink attribtue header
 *
 * Attribute Construction:
 *   nla_reserve(skb, type, len)    reserve skb tailroom for an attribute
 *   nla_put(skb, type, len, data)    add attribute to skb
 *
 * Attribute Construction for Basic Types:
 *   nla_put_u8(skb, type, value)    add u8 attribute to skb
 *   nla_put_u16(skb, type, value)    add u16 attribute to skb
 *   nla_put_u32(skb, type, value)    add u32 attribute to skb
 *   nla_put_u64(skb, type, value)    add u64 attribute to skb
 *   nla_put_string(skb, type, str)    add string attribute to skb
 *   nla_put_flag(skb, type)        add flag attribute to skb
 *   nla_put_msecs(skb, type, jiffies)    add msecs attribute to skb
 *
 * Exceptions Based Attribute Construction:
 *   NLA_PUT(skb, type, len, data)    add attribute to skb
 *   NLA_PUT_U8(skb, type, value)    add u8 attribute to skb
 *   NLA_PUT_U16(skb, type, value)    add u16 attribute to skb
 *   NLA_PUT_U32(skb, type, value)    add u32 attribute to skb
 *   NLA_PUT_U64(skb, type, value)    add u64 attribute to skb
 *   NLA_PUT_STRING(skb, type, str)    add string attribute to skb
 *   NLA_PUT_FLAG(skb, type)        add flag attribute to skb
 *   NLA_PUT_MSECS(skb, type, jiffies)    add msecs attribute to skb
 *
 *   The meaning of these functions is equal to their lower case
 *   variants but they jump to the label nla_put_failure in case
 *   of a failure.
 *
 * Nested Attributes Construction:
 *   nla_nest_start(skb, type)        start a nested attribute
 *   nla_nest_end(skb, nla)        finalize a nested attribute
 *   nla_nest_cancel(skb, nla)        cancel nested attribute construction
 *
 * Attribute Length Calculations:
 *   nla_attr_size(payload)        length of attribute w/o padding
 *   nla_total_size(payload)        length of attribute w/ padding
 *   nla_padlen(payload)        length of padding
 *
 * Attribute Payload Access:
 *   nla_data(nla)            head of attribute payload
 *   nla_len(nla)            length of attribute payload
 *
 * Attribute Payload Access for Basic Types:
 *   nla_get_u8(nla)            get payload for a u8 attribute
 *   nla_get_u16(nla)            get payload for a u16 attribute
 *   nla_get_u32(nla)            get payload for a u32 attribute
 *   nla_get_u64(nla)            get payload for a u64 attribute
 *   nla_get_flag(nla)            return 1 if flag is true
 *   nla_get_msecs(nla)            get payload for a msecs attribute
 *
 * Attribute Misc:
 *   nla_memcpy(dest, nla, count)    copy attribute into memory
 *   nla_memcmp(nla, data, size)    compare attribute with memory area
 *   nla_strlcpy(dst, nla, size)    copy attribute to a sized string
 *   nla_strcmp(nla, str)        compare attribute with string
 *
 * Attribute Parsing:
 *   nla_ok(nla, remaining)        does nla fit into remaining bytes?
 *   nla_next(nla, remaining)        get next netlink attribute
 *   nla_validate()            validate a stream of attributes
 *   nla_find()                find attribute in stream of attributes
 *   nla_parse()            parse and validate stream of attrs
 *   nla_parse_nested()            parse nested attribuets
 *   nla_for_each_attr()        loop over all attributes
 *========================================================================= 


= 삭제 대비 카피

Generic Netlink sockets - example code

If you want to use netlink as a userspace-kernelspace interface for your own non-networking custom use, make sure to go the Generic Netlink path - get a family id assigned and then used that to exchange messages between your userspace and kernelspace. That said, its better to just use Netlink Protocol Library Suite (libnl). If for some extremely compelling reason you can't, use libnl, here is some sample code to get you started.
Its based on Ariane Kellar's code from here. I have simplified and commented the userspace side code a lot. The kernel space code is mostly unchanged. The kernel side code required a minor change in genlmsg_unicast() call to ensure compatibility with the newer kernel versions.


nl_kern.c :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <net/genetlink.h>
#include <linux/module.h>
#include <linux/kernel.h>

//Code based on http://people.ee.ethz.ch/~arkeller/linux/multi/kernel_user_space_howto-3.html

/* attributes (variables):
 * the index in this enum is used as a reference for the type,
 * userspace application has to indicate the corresponding type
 * the policy is used for security considerations 
 */
enum {
 DOC_EXMPL_A_UNSPEC,
 DOC_EXMPL_A_MSG,
    __DOC_EXMPL_A_MAX,
};
#define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1)

/* attribute policy: defines which attribute has which type (e.g int, char * etc)
 * possible values defined in net/netlink.h 
 */
static struct nla_policy doc_exmpl_genl_policy[DOC_EXMPL_A_MAX + 1] = {
 [DOC_EXMPL_A_MSG] = { .type = NLA_NUL_STRING },
};

#define VERSION_NR 1
//family definition
static struct genl_family doc_exmpl_gnl_family = {
 .id = GENL_ID_GENERATE,         //Genetlink should generate an id
 .hdrsize = 0,
 .name = "CONTROL_EXMPL",        //The name of this family, used by userspace application
 .version = VERSION_NR,          //Version number  
 .maxattr = DOC_EXMPL_A_MAX,
};

/* commands: enumeration of all commands (functions), 
 * used by userspace application to identify command to be executed
 */
enum {
 DOC_EXMPL_C_UNSPEC,
 DOC_EXMPL_C_ECHO,
 __DOC_EXMPL_C_MAX,
};
#define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1)


//An echo command, receives a message, prints it and sends another message back
int doc_exmpl_echo(struct sk_buff *skb_2, struct genl_info *info) {
 struct nlattr *na;
 struct sk_buff *skb;
 int rc;
 void *msg_head;
 char * mydata;
 
 if (info == NULL) {
  goto out;
 }
  
    /* For each attribute there is an index in info->attrs which points to a nlattr structure
     * in this structure the data is given
     */
    na = info->attrs[DOC_EXMPL_A_MSG];
    if (na) {
  mydata = (char *)nla_data(na);
  if (mydata == NULL) {
   printk("error while receiving data\n");
  } else {
   printk("received: %s\n", mydata);
  }
 } else {
  printk("no info->attrs %i\n", DOC_EXMPL_A_MSG);
 }

    //Send a message back
    //Allocate some memory, since the size is not yet known use NLMSG_GOODSIZE
 skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 if (skb == NULL) {
  goto out;
 }

 //Create the message headers
    /* arguments of genlmsg_put: 
       struct sk_buff *, 
       int (sending) pid, 
       int sequence number, 
       struct genl_family *, 
       int flags, 
       u8 command index (why do we need this?)
    */
 msg_head = genlmsg_put(skb, 0, info->snd_seq+1, &doc_exmpl_gnl_family, 0, DOC_EXMPL_C_ECHO);
 if (msg_head == NULL) {
  rc = -ENOMEM;
  goto out;
 }
 //Add a DOC_EXMPL_A_MSG attribute (actual value to be sent)
 rc = nla_put_string(skb, DOC_EXMPL_A_MSG, "Hello World from kernel space");
 if (rc != 0) {
  goto out;
 }
 
 //Finalize the message
 genlmsg_end(skb, msg_head);

    //Send the message back
 rc = genlmsg_unicast(genl_info_net(info), skb,info->snd_pid );
 if (rc != 0) {
  goto out;
 }
 return 0;

 out:
 printk("An error occured in doc_exmpl_echo:\n");
 return 0;
}

//Commands: mapping between the command enumeration and the actual function
struct genl_ops doc_exmpl_gnl_ops_echo = {
 .cmd = DOC_EXMPL_C_ECHO,
 .flags = 0,
 .policy = doc_exmpl_genl_policy,
 .doit = doc_exmpl_echo,
 .dumpit = NULL,
};

static int __init gnKernel_init(void) {
 int rc;
 printk("Generic Netlink Example Module inserted.\n");
        
    //Register the new family
 rc = genl_register_family(&doc_exmpl_gnl_family);
 if (rc != 0) {
  goto failure;
 }
 //Register functions (commands) of the new family
 rc = genl_register_ops(&doc_exmpl_gnl_family, &doc_exmpl_gnl_ops_echo);
 if (rc != 0) {
  printk("Register ops: %i\n",rc);
  genl_unregister_family(&doc_exmpl_gnl_family);
  goto failure;
 }
 return 0; 
failure:
 printk("An error occured while inserting the generic netlink example module\n");
 return -1;
}

static void __exit gnKernel_exit(void) {
 int ret;
 printk("Generic Netlink Example Module unloaded.\n");
 
 //Unregister the functions
 ret = genl_unregister_ops(&doc_exmpl_gnl_family, &doc_exmpl_gnl_ops_echo);
 if(ret != 0) {
  printk("Unregister ops: %i\n",ret);
  return;
 }

    //Unregister the family
 ret = genl_unregister_family(&doc_exmpl_gnl_family);
 if(ret !=0) {
  printk("Unregister family %i\n",ret);
 }
}

module_init(gnKernel_init);
module_exit(gnKernel_exit);
MODULE_LICENSE("GPL");

     




nl_user.c :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>

#include <linux/genetlink.h>

//Code based on http://people.ee.ethz.ch/~arkeller/linux/multi/kernel_user_space_howto-3.html

/* Generic macros for dealing with netlink sockets. Might be duplicated
 * elsewhere. It is recommended that commercial grade applications use
 * libnl or libnetlink and use the interfaces provided by the library
 */
#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))

#define MESSAGE_TO_KERNEL "Hello World!"

//Variables used for netlink
int nl_fd;  //netlink socket's file descriptor
struct sockaddr_nl nl_address; //netlink socket address
int nl_family_id; //The family ID resolved by the netlink controller for this userspace program
int nl_rxtx_length; //Number of bytes sent or received via send() or recv()
struct nlattr *nl_na; //pointer to netlink attributes structure within the payload 
struct { //memory for netlink request and response messages - headers are included
    struct nlmsghdr n;
    struct genlmsghdr g;
    char buf[256];
} nl_request_msg, nl_response_msg;


int main(void) {
//Step 1: Open the socket. Note that protocol = NETLINK_GENERIC
    nl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
    if (nl_fd < 0) {
  perror("socket()");
  return -1;
    }

//Step 2: Bind the socket.
 memset(&nl_address, 0, sizeof(nl_address));
 nl_address.nl_family = AF_NETLINK;
 nl_address.nl_groups = 0;

 if (bind(nl_fd, (struct sockaddr *) &nl_address, sizeof(nl_address)) < 0) {
  perror("bind()");
  close(nl_fd);
  return -1;
 }

//Step 3. Resolve the family ID corresponding to the string "CONTROL_EXMPL"
    //Populate the netlink header
    nl_request_msg.n.nlmsg_type = GENL_ID_CTRL;
    nl_request_msg.n.nlmsg_flags = NLM_F_REQUEST;
    nl_request_msg.n.nlmsg_seq = 0;
    nl_request_msg.n.nlmsg_pid = getpid();
    nl_request_msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
    //Populate the payload's "family header" : which in our case is genlmsghdr
    nl_request_msg.g.cmd = CTRL_CMD_GETFAMILY;
    nl_request_msg.g.version = 0x1;
    //Populate the payload's "netlink attributes"
 nl_na = (struct nlattr *) GENLMSG_DATA(&nl_request_msg);
    nl_na->nla_type = CTRL_ATTR_FAMILY_NAME;
    nl_na->nla_len = strlen("CONTROL_EXMPL") + 1 + NLA_HDRLEN;
    strcpy(NLA_DATA(nl_na), "CONTROL_EXMPL"); //Family name length can be upto 16 chars including \0
    
    nl_request_msg.n.nlmsg_len += NLMSG_ALIGN(nl_na->nla_len);

 memset(&nl_address, 0, sizeof(nl_address));
 nl_address.nl_family = AF_NETLINK;

 //Send the family ID request message to the netlink controller
 nl_rxtx_length = sendto(nl_fd, (char *) &nl_request_msg, nl_request_msg.n.nlmsg_len,
  0, (struct sockaddr *) &nl_address, sizeof(nl_address));
 if (nl_rxtx_length != nl_request_msg.n.nlmsg_len) {
  perror("sendto()");
  close(nl_fd);
  return -1;
    }

 //Wait for the response message
    nl_rxtx_length = recv(nl_fd, &nl_response_msg, sizeof(nl_response_msg), 0);
    if (nl_rxtx_length < 0) {
        perror("recv()");
        return -1;
    }

    //Validate response message
    if (!NLMSG_OK((&nl_response_msg.n), nl_rxtx_length)) {
        fprintf(stderr, "family ID request : invalid message\n");
        return -1;
    }
    if (nl_response_msg.n.nlmsg_type == NLMSG_ERROR) { //error
        fprintf(stderr, "family ID request : receive error\n");
        return -1;
    }

    //Extract family ID
    nl_na = (struct nlattr *) GENLMSG_DATA(&nl_response_msg);
    nl_na = (struct nlattr *) ((char *) nl_na + NLA_ALIGN(nl_na->nla_len));
    if (nl_na->nla_type == CTRL_ATTR_FAMILY_ID) {
        nl_family_id = *(__u16 *) NLA_DATA(nl_na);
    }

//Step 4. Send own custom message
 memset(&nl_request_msg, 0, sizeof(nl_request_msg));
 memset(&nl_response_msg, 0, sizeof(nl_response_msg));

    nl_request_msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
    nl_request_msg.n.nlmsg_type = nl_family_id;
    nl_request_msg.n.nlmsg_flags = NLM_F_REQUEST;
    nl_request_msg.n.nlmsg_seq = 60;
    nl_request_msg.n.nlmsg_pid = getpid();
    nl_request_msg.g.cmd = 1; //corresponds to DOC_EXMPL_C_ECHO;
        
    nl_na = (struct nlattr *) GENLMSG_DATA(&nl_request_msg);
    nl_na->nla_type = 1; // corresponds to DOC_EXMPL_A_MSG
    nl_na->nla_len = sizeof(MESSAGE_TO_KERNEL)+NLA_HDRLEN; //Message length
    memcpy(NLA_DATA(nl_na), MESSAGE_TO_KERNEL, sizeof(MESSAGE_TO_KERNEL));
    nl_request_msg.n.nlmsg_len += NLMSG_ALIGN(nl_na->nla_len);

    memset(&nl_address, 0, sizeof(nl_address));
 nl_address.nl_family = AF_NETLINK;

 //Send the custom message
 nl_rxtx_length = sendto(nl_fd, (char *) &nl_request_msg, nl_request_msg.n.nlmsg_len,
  0, (struct sockaddr *) &nl_address, sizeof(nl_address));
 if (nl_rxtx_length != nl_request_msg.n.nlmsg_len) {
  perror("sendto()");
  close(nl_fd);
  return -1;
    }
    printf("Sent to kernel: %s\n",MESSAGE_TO_KERNEL);

    //Receive reply from kernel
    nl_rxtx_length = recv(nl_fd, &nl_response_msg, sizeof(nl_response_msg), 0);
    if (nl_rxtx_length < 0) {
        perror("recv()");
        return -1;
    }

 //Validate response message
    if (nl_response_msg.n.nlmsg_type == NLMSG_ERROR) { //Error
        printf("Error while receiving reply from kernel: NACK Received\n");
        close(nl_fd);
        return -1;
    }
    if (nl_rxtx_length < 0) {
        printf("Error while receiving reply from kernel\n");
        close(nl_fd);
        return -1;
    }
    if (!NLMSG_OK((&nl_response_msg.n), nl_rxtx_length)) {
        printf("Error while receiving reply from kernel: Invalid Message\n");
        close(nl_fd);
     return -1;
 }

    //Parse the reply message
    nl_rxtx_length = GENLMSG_PAYLOAD(&nl_response_msg.n);
    nl_na = (struct nlattr *) GENLMSG_DATA(&nl_response_msg);
    printf("Kernel replied: %s\n",(char *)NLA_DATA(nl_na));

//Step 5. Close the socket and quit
    close(nl_fd);
    return 0;
}



Makefile :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
obj-m += nl_kern.o
nl_kern-objs := kern/nl_kern.o

all: kernel-module-uninstall kernel-clean-ring-buffer kernel-build kernel-clean-temporary kernel-module-install user-build
 @tput setaf 3
 @echo "    done: all"
 @tput sgr0
clean: kernel-module-uninstall kernel-clean user-clean
 @tput setaf 3
 @echo "    done: clean"
 @tput sgr0
 
 
 
kernel-build:
 @tput setaf 1
 @echo "    kernel-build"
 @tput sgr0
 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
kernel-clean:
 @tput setaf 1
 @echo "    kernel-clean"
 @tput sgr0
 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
kernel-clean-temporary:
 @tput setaf 1
 @echo "    kernel-clean-temporary"
 @tput sgr0
 -rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
 -rm -rf kern/*.o kern/*~ kern/core kern/.depend kern/.*.cmd kern/*.mod.c kern/.tmp_versions
 -rm -rf Module.symvers modules.order
kernel-module-install:
 @tput setaf 1
 @echo "    kernel-module-install"
 @tput sgr0
 -sudo insmod nl_kern.ko
kernel-module-uninstall:
 @tput setaf 1
 @echo "    kernel-module-uninstall"
 @tput sgr0
 -sudo rmmod nl_kern
kernel-clean-ring-buffer:
 @tput setaf 1
 @echo "    kernel-clean-ring-buffer"
 @tput sgr0
 sudo dmesg -c > /dev/null

 
 
user-build:
 @tput setaf 1
 @echo "    user-build"
 @tput sgr0
 gcc user/nl_user.c -o nl_user.out
user-clean:
 @tput setaf 1
 @echo "    user-clean"
 @tput sgr0
 rm -rf *.out

Keep the above source files organized in the folders like this if you want to use the above Makefile:



반응형

'프로그램... > 프로....Kernel' 카테고리의 다른 글

[Memory] 커널 메모리 관리  (0) 2017.09.19
[Timer] hrtimer  (0) 2015.04.13
[Kernel-Document]  (0) 2014.10.31
[Kernel-Make] the Kernel Build System (kbuild)  (0) 2014.10.31
[고급 스킬] from Linux Kernel  (0) 2014.10.29