1. 下载源代码包

http://vault.centos.org 下载内核源代码RPM包

2. 安装源代码包

[root@wcg-9-73 df]# rpm -ivh kernel-3.10.0-1062.el7.src.rpm

执行命令后会生成/root/rpmbuild路径,包含SPECS和SOURCES

3. 修改源码

[root@wcg-9-73 df]# cd /root/rpmbuild/SOURCES
[root@wcg-9-73 SOURCES]# xz -d linux-3.10.0-1062.el7.tar.xz
[root@wcg-9-73 SOURCES]# tar -xvf linux-3.10.0-1062.el7.tar
#将修改后的代码替换
[root@wcg-9-73 SOURCES]# cd linux-3.10.0-1062.el7/
[root@wcg-9-73 linux-3.10.0-1062.el]# cd net/ipv4/
[root@wcg-9-73 ipv4]# rm -rf udp.c && cp -rf /root/df/udp.c .
[root@wcg-9-73 ipv4]# cd ../../include/uapi/linux/
[root@wcg-9-73 linux]# rm -rf udp.h && cp -rf /root/df/udp.h .
[root@wcg-9-73 linux]# cd ../../../
[root@wcg-9-73 SOURCES]# tar -cvf linux-3.10.0-1062.el7.tar linux-3.10.0-1062.el7
[root@wcg-9-73 SOURCES]# xz -zv linux-3.10.0-1062.el7.tar

4. 编译打包

[root@wcg-9-73 SOURCES]# cd ..
[root@wcg-9-73 rpmbuild]# nohup rpmbuild -bb SPECS/kernel.spec &
#只编译kernel rpm
[root@wcg-9-73 rpmbuild]# rpmbuild -bb --without debug --without debuginfo --without tools --without perf --without doc SPECS/kernel.spec

kernel-devel和kernel-headers用来开发ko模块,要用到Module.symvers

5. 单独编译kernel

# cd /root/rpmbuild/BUILD/kernel-3.10.0-327.36.3.el7/linux-3.10.0-327.36.3.el7.x86_64
# make -j20 bzImage

6. 替换kernel进行测试

# cp arch/x86/boot/bzImage /boot
# cd /boot
# mv bzImage vmlinuz-3.10.0-327.36.3.el7.x86_64
# reboot

7. 修改的源码

udp.h

/*
 * INET     An implementation of the TCP/IP protocol suite for the LINUX
 *      operating system.  INET is implemented using the  BSD Socket
 *      interface as the means of communication with the user level.
 *
 *      Definitions for the UDP protocol.
 *
 * Version: @(#)udp.h   1.0.2   04/28/93
 *
 * Author:  Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */
#ifndef _UAPI_LINUX_UDP_H
#define _UAPI_LINUX_UDP_H

#include <linux/types.h>

struct udphdr {
    __be16  source;
    __be16  dest;
    __be16  len;
    __sum16 check;
};

/* UDP socket options */
#define UDP_CORK    1   /* Never send partially complete segments */
#define UDP_ENCAP   100 /* Set the socket to accept encapsulated packets */
#define UDP_NO_CHECK6_TX 101    /* Disable sending checksum for UDP6X */
#define UDP_NO_CHECK6_RX 102    /* Disable accpeting checksum for UDP6 */

/* UDP encapsulation types */
#define UDP_ENCAP_ESPINUDP_NON_IKE  1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
#define UDP_ENCAP_ESPINUDP  2 /* draft-ietf-ipsec-udp-encaps-06 */
#define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */

// add by dongfeng 2020-04-13
#define UDP_ENCAP_GTP_DOWN 7
#define UDP_ENCAP_GTP_UP 8
// end add

#endif /* _UAPI_LINUX_UDP_H */


udp.c

...
int sysctl_udp_wmem_min __read_mostly;
EXPORT_SYMBOL(sysctl_udp_wmem_min);

atomic_long_t udp_memory_allocated;
EXPORT_SYMBOL(udp_memory_allocated);

// add by dongfeng 2020-04-13
int (*gtprelay_ko_up_rx_hook)(struct sk_buff *, int ) = NULL;
EXPORT_SYMBOL(gtprelay_ko_up_rx_hook);

int (*gtprelay_ko_down_rx_hook)(struct sk_buff *,int ) = NULL;
EXPORT_SYMBOL(gtprelay_ko_down_rx_hook);
// end add


#define MAX_UDP_PORTS 65536
#define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN)
...

...
int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
    struct udp_sock *up = udp_sk(sk);
    int is_udplite = IS_UDPLITE(sk);

    /*
     *  Charge it to the socket, dropping if the queue is full.
     */
    if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
        goto drop;
    nf_reset(skb);

    if (static_key_false(&udp_encap_needed) && up->encap_type) {
        int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);

        /*
         * This is an encapsulation socket so pass the skb to
         * the socket's udp_encap_rcv() hook. Otherwise, just
         * fall through and pass this up the UDP socket.
         * up->encap_rcv() returns the following value:
         * =0 if skb was successfully passed to the encap
         *    handler or was discarded by it.
         * >0 if skb should be passed on to UDP.
         * <0 if skb should be resubmitted as proto -N
         */

        /* if we're overly short, let UDP handle it */
        encap_rcv = ACCESS_ONCE(up->encap_rcv);
        if (encap_rcv) {
            int ret;

            /* Verify checksum before giving to encap */
            if (udp_lib_checksum_complete(skb))
                goto csum_error;

            ret = encap_rcv(sk, skb);
            if (ret <= 0) {
                UDP_INC_STATS_BH(sock_net(sk),
                         UDP_MIB_INDATAGRAMS,
                         is_udplite);
                return -ret;
            }
        }
        
        // add by dongfeng 2020-04-13
        switch(up->encap_type) {
            case UDP_ENCAP_GTP_DOWN:
                 // printk("UDP_ENCAP_GTP_DOWN \n");
                if(gtprelay_ko_down_rx_hook) {
                    int ret1 = 0;
                    ret1 = gtprelay_ko_down_rx_hook(skb,1);
                    if(ret1 == 1) {
                        break;
                    } else if(ret1 == 2) {
                        kfree_skb(skb);
                        return 0;
                    } else {
                        return 0;
                    }
                }
                break;
            case UDP_ENCAP_GTP_UP:
                //printk("UDP_ENCAP_GTP_UP \n");
                if(gtprelay_ko_up_rx_hook) {
                    int ret1 = 0;
                    ret1 = gtprelay_ko_up_rx_hook(skb,1);
                    if(ret1 == 1) {
                        break;
                    } else if(ret1 == 2) {
                         kfree_skb(skb);
                         return 0;
                    } else {
                        return 0;
                    }
                }
                break;
            default:
                break;
        }
        // end add

        /* FALLTHROUGH -- it's a UDP Packet */
    }
...


...
/*
 *  Socket option code for UDP
 */
int udp_lib_setsockopt(struct sock *sk, int level, int optname,
               char __user *optval, unsigned int optlen,
               int (*push_pending_frames)(struct sock *))
{
    struct udp_sock *up = udp_sk(sk);
    int val, valbool;
    int err = 0;
    int is_udplite = IS_UDPLITE(sk);

    if (optlen < sizeof(int))
        return -EINVAL;

    if (get_user(val, (int __user *)optval))
        return -EFAULT;

    valbool = val ? 1 : 0;

    switch (optname) {
    case UDP_CORK:
        if (val != 0) {
            up->corkflag = 1;
        } else {
            up->corkflag = 0;
            lock_sock(sk);
            push_pending_frames(sk);
            release_sock(sk);
        }
        break;

    case UDP_ENCAP:
        switch (val) {
        case 0:
        case UDP_ENCAP_ESPINUDP:
        case UDP_ENCAP_ESPINUDP_NON_IKE:
            up->encap_rcv = xfrm4_udp_encap_rcv;
            /* FALLTHROUGH */
        case UDP_ENCAP_L2TPINUDP:
            up->encap_type = val;
            udp_encap_enable();
            break;
        // add by dongfeng 2020-04-13
        case UDP_ENCAP_GTP_DOWN:
        case UDP_ENCAP_GTP_UP:
            up->encap_type = val;
            udp_encap_enable();
            //printk("udp_setsockopt %d\n",up->encap_type);
            break;
        // end add   

        default:
            err = -ENOPROTOOPT;
            break;
        }
        break;

    case UDP_NO_CHECK6_TX:
        up->no_check6_tx = valbool;
        break;

    case UDP_NO_CHECK6_RX:
        up->no_check6_rx = valbool;
        break;

    /*
     *  UDP-Lite's partial checksum coverage (RFC 3828).
     */
    /* The sender sets actual checksum coverage length via this option.
     * The case coverage > packet length is handled by send module. */
    case UDPLITE_SEND_CSCOV:
        if (!is_udplite)         /* Disable the option on UDP sockets */
            return -ENOPROTOOPT;
        if (val != 0 && val < 8) /* Illegal coverage: use default (8) */
            val = 8;
        else if (val > USHRT_MAX)
            val = USHRT_MAX;
        up->pcslen = val;
        up->pcflag |= UDPLITE_SEND_CC;
        break;
...