用2倍的时间再次搭建起ikev2服务

事情的起因是不小心更新了手机上的spark(一款非常舒服的邮件app),新版的app第一次登陆需要访问它们架在google云上的服务器,国内理所当然的就无法使用了。

从此心里埋下一根刺,必须要在手机上解决VPN的事情。那就开始安装strongswan呗。按理说对着教程安装一个服务应该难不倒我(况且3年前我就成功安装过ikev2)。最后用时比3年前那次多了1倍还多。。。

中间的曲折就不细说了,捡重要的说。
1、ikev2服务要用到2个私钥2个证书。
root.key.pem, root.pem, server.key.pem, server.pem
利用私钥生成证书。私钥root.key.pem生成根证书root.pem,生成根证书后就不在使用了该私钥了,自己藏藏好。服务器上用的server.pem证书是通过root.pem根证书签发。因为root.pem根证书是私人小作坊生成的,它签发的东西大家都不认可,所以需要手动将root.pem安装到客户端(比如手机、mac),这样客户端就认可server.pem了。
划重点:用认证机构生成的server_niubi.pem所有客户端默认就认可,可以省略手动安装认证机构根证书的步骤,挺方便的。利用acme.sh可一站式自动申请Let’s Encrypt证书。

2、不知道是年纪大了思维钝化了,还是脑子笨了。服务搭建完之后连不上服务器,只知道不停的google各种安装教程,不停的修改配置文件,不停的重启服务再试。走了许许多多弯路,直到最后才想起来看下日志文件,log中明明白白、清清楚楚的写着各种不成功的原因,之后就迎刃而解了。这里详细的记载了log的用法。

3、参考过的网页千千万,留几个最经典的。手把手教你在Ubuntu上安装ikev2在centos和Ubuntu上一键安装ikev2strongswan官方教你写no_use.mobileconfig配置文件

到这里本文应该结束了。最后说一下写本文的引子。所有服务搭建好之后,在linode后台的stackscript里看到了linode官方认可的一键部署ikev2的脚本,它用的是libreswan,目测应该是100%可用。我又浪费了一个宝贵的周末。

全文完。

内核抢占和中断

以前一直不理解什么是内核抢占,现在好像懂了。

本文尝试解释什么是内核可抢占以及可抢占和可中断的区别。

首先被中断不是被抢占,中断和抢占是两个概念。抢占必须涉及进程上下文的切换,而中断是在中断上下文。

所谓可抢占抢的是进程上下文,人人都争取上台。可中断指的是是否可以中断当前CPU而进入我的中断处理函数。

如果内核是不可抢占的(比如说2.4的内核),一旦切进内核态,只要代码不是主动释放CPU它就可以一直占着CPU。例外,虽不可抢占,但若此时发生中断,代码还是要交出CPU,但是中断返回之后,代码又能霸占CPU了,此为可中断但不可抢占。

如果内核是可抢占的(比如2.6或之后的内核),上述情况就不会发生了。内核抢占发生在以下3种情况:

1. 从中断返回内核态时,若此时可抢占,则会强制调用schedule(),尝试抢占,被中断的内核代码不一定能继续霸着CPU。

2.内核变成可抢占状态,此时也会尝试抢占。

3.内核代码主动调用schedule()。

虽然2.6的内核提供内核抢占,但是也提供关闭的手段。是否可抢占是由preemt_count变量控制(per-cpu),有锁这个计数就+1,释放锁就-1.为0才是可抢占。每当释放锁的时候都会检查是否为0,为0则尝试抢占。

 

+++++++++++++++++++分割线++++++++++++++++++++++++++++++++

关于中断

中断分为上下两个部分。是为中断上半部(top half)、下半部(bottom half)。

上半部处理紧要事情。比如:通知硬件“我知道你请求中断了,继续干活去”,然后从设备缓冲区拷贝数据到内存。

下半部处理不那么要紧的任务。比如:网卡上来的数据推进协议栈,然后推给上层应用程序。

当前的内核有三种下半部的实现方式:softirq、tasklet、working queue。

         名称

上下文

特点

概述
Softirq

中断上下文

可中断不可睡眠 速度最快。同一个Softirq可能会同时运行在多个核上,必须非常小心的处理数据同步
Tasklet

中断上下文

可中断不可睡眠 基于Softirq实现,同一类的Tasklet不会被同时运行,编程代价小
Work queue

进程上下文

可中断可睡眠

基于内核线程实现

 

 

每天记一点,进步看的见。

KGDB && Build Ubuntu kernel

关于KGDB:GDB是GUN的调试器,用来调试普通程序。KGDB是用来调试操作系统内核的。当我还在念小学的时候,Linus严辞拒绝KGDB进入主线内核的,理由是:真正懂内核的人不需要工具来调试,人脑就能调代码[1]。可是到了2.6.26时代,却已经欣然接受KGDB,很想知道是谁说服了那个顽固的天才。

下面开始在Ubuntu 10.04下快乐的使用KGDB。

为什么是Ubuntu 10.04?我用过的发行版不多,也就Ubuntu、Archlinux、Redhat、Centos、Fedora、LFS。Ubuntu并不是最好用的,很多地方都不符合我的习惯,但是,因为手边正好有一张Ubuntu的推广光盘,这张质量上乘的推广光盘使我把附近能用的机器都装上了Ubuntu。光盘安装的便利性是各种硬盘安装、网络安装、U盘安装等繁琐手段无法比拟的。于是乎,我被Ubuntu俘虏了。

真要我说Ubuntu最吸引我的地方,大概就是它那个默认的红色配色了,看着很舒服。字体也刚刚好。

Ubuntu 不太适合搞KGDB,因为在Ubuntu上换内核特别麻烦。注意,是特别麻烦。

10.04的内核默认已经打开了KGDB选项,但是因为发行版不提供原始的vmlinux文件,因此需要重做一个(反正已经重编了内核,顺手就换下内核,好处是可以完美match 符号表,自己动手编的vmlinux文件和官方的核不能100%契合)。

官方的wiki上提供了两种编译内核的方式,一种是编Ubuntu kernel一种是编主线kernel

图省事我编的是Ubuntu kernel。

首先拿到内核源码,推荐使用git方式。

Git路径如下:

quantal

git://kernel.ubuntu.com/ubuntu/ubuntu-quantal.git

precise

git://kernel.ubuntu.com/ubuntu/ubuntu-precise.git

oneiric

git://kernel.ubuntu.com/ubuntu/ubuntu-oneiric.git

natty

git://kernel.ubuntu.com/ubuntu/ubuntu-natty.git

lucid

git://kernel.ubuntu.com/ubuntu/ubuntu-lucid.git

hardy

git://kernel.ubuntu.com/ubuntu/ubuntu-hardy.git

10.04 是lucid,所以执行

$git clone git://kernel.ubuntu.com/ubuntu/ubuntu-lucid.git

然后切换至对应的tag上。查看版本

$uname -a

Linux hacklu-desktop 2.6.32-21-generic #32-Ubuntu SMP

所以对应的tag是Ubuntu-2.6.32-21.32。

$git checkout -b my_kernel Ubuntu-2.6.32-21.32

编译选项最好在发行版的基础上修改

$cp /boot/config-2.6.32-21-generic .config

$make oldconfig

在这基础上修改自定义的配置(调试内核,需要把CONFIG_DEBUG_RODATA关闭,代码段的只读属性不去掉,KGDB无法下断点。因为断点是通过把欲断处指令改成INT3来实现)

$make menuconfig

$make-kpkg clean # only needed if you want to do a "clean" build

$cp Ubuntu-kernel-src/debian/control-scripts/{postinst,postrm,preinst,prerm} ~/kernel-package/pkg/image/

$ cp Ubuntu-kernel-src /debian/control-scripts/headers-postinst ~/kernel-package/pkg/headers/

$CONCURRENCY_LEVEL=2  fakeroot make-kpkg --initrd --append-to-version=-hacklu.v1 --overlay-dir=~/kernel-package/  kernel_image kernel_headers

 

解释下, CONCURRENCY_LEVEL=2 相当于平时的make -j2 编译速度加快。

fakeroot 是make-kpkg以为你是root

--append-to-version=-hacklu.v1 后面的字符串会自动加在编译好的内核版本后面

--overlay-dir=~/kernel-package/  make-kpkg 命令需要这个选项指定定制脚本路径,如果没有这一项,编译出来的内核缺少initramfs。

Kernel_image 表示编译image.deb

Kernel_header表示编译header.deb

命令执行完毕会在当前目录的上一级生成两个deb包,分别安装即可

$sudo dpkg -i *.deb

Image.deb会根据控制脚本自动生成initramfs,并更新grub,重启即可切换至新编出的内核。

 

此刻KGDB 和vmlinux都已经准备好了。如果有串口线则可调试实体机器,不然就放在vmware中调试。

Vmware中安装好一台ubuntu10.04的系统做被调试机,然后add device—》serial port—》named pipe

如下,记得要勾上Yield CPU on poll。

如果调试机也是虚拟机,类似添加串口设备,server和client互换。

如果调试机是局域网内一台物理机器,则可以利用命名管道转网络工具[2]把虚拟机中的被调试机器的串口转发到局域网中去。

在被调试机器上执行如下指令

$sudo -s

#echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc   #指定通信串口号

#echo g > /proc/sysrq-trigger  #挂起被调试机器,产生kgdb_breakpoint中断。此时调试端gdb可以连入

在调试机器上执行如下

$gdb vmlinux

$target remote /dev/ttyS0

之后就可以开心的使用GDB调试内核了。

Ps:最好使用Ubuntu自带的gdb来调试,10.04的内核跟7.2以上的GDB不合拍。

 

 

[1] Linus say: Without a debugger, you basically have
to go the next step: understand what the program does. Not just that
particular line. https://lkml.org/lkml/2000/9/6/65
[2] Named Pipe TCP Proxy Utility http://shvechkov.tripod.com/nptp.html

LFS && Raspberry && pin

最近干了这三件事。记录之。

LFS:Linux from scratch。

LFS是我的一个心结,很久之前就说要好好做一遍这个,却一直借口没有时间,其实真正做下来也就花了25个小时左右,两次机房血战就差不多能做一次了。

LFS的基本思想是借助一台已有的linux环境,从碎片开始安装linux。自己搭建工具链,自己编译内核,自己编译shell。所有的一切都是从源代码开始一点一点慢慢编译。

做LFS学到的东西比我预期少了点,init之后的启动流程还是云里雾里,估计这阶段是不会认真去读那堆启动脚本了,留个遗憾。

最大的收获就是工具链的制作原理以及常用命令都是来自哪个包。

GNU的工具链分为三个部分,binutil,Glibc,GCC。

GCC负责编译,把c语言代码编译成汇编语言。这期间会用到C库(glibc)。

Glibc主要包括C库,还有动态加载器(/lib/ld-linux.so.2),此动态加载器负责加载二进制文件到进程地址空间。

Binutil是二进制工具,处理二进制文件。包括ar,as(汇编器,把汇编文件翻译成二进制文件),ld(静态链接器),以及我最喜欢的反编译objdump。

这三者的关系如下:

Gcc编译过程需要链接Glibc。

Binutil编译过程需要链接Glibc。

Glibc是自包含的,编译过程不需要链接到Glibc,但是它需要工具链来编译自己,并受到工具链的影响,工具链是什么?工具链就是gcc+glibc+binutil(严格来讲编译glibc时不需要宿主的glibc,只要gcc和binutil就可以)。

基本上算是循环依赖= =!。

那么如何制作一个pure的工具链?LFS曾今的做法也是有缺陷的,后来被一名内核黑客提出了改进办法[1]。

现今的办法如下:

(注:gcc0表示第0代gcc,也就是宿主上原来的gcc程序,gcc1表示第一次编译出来的gcc。其他同)

gcc0 + glibc0 + binutil0 -> binutil1,gcc1 (一代gcc和binutil链接都是宿主上的glibc,所以受宿主的影响)

gcc1 + binutil1 -> glibc1 (一代glibc 只受一代gcc影响,开始隔离宿主)

gcc1 + glibc1 + binutil1 -> binutil2, gcc2 (二代工具链用的是新生成的glibc1)

gcc2,binutil2,glibc1 三者构成了临时编译环境。用这套工具链生成了一堆临时环境需要用到的各种工具,比如make,sed等等。

Gcc2 + binutil2 -> glibc2

Gcc2 + binutil2 + glibc2 -> gcc3 ,binutil3

Gcc3,binutil3,glibc2 三者构成了最终LFS的编译环境,LFS上最后运行的所有程序都是来自这三个家伙。

(吐槽一句,其实无论怎么折腾,这也是个鸡生蛋蛋生鸡的问题,只要在gcc0中做手脚,后面的gcc永远不会干净。在此向伟大的C语言之父Dennis Ritchie致敬。)

LFS意外收获:

  1. cp abc{,.new}  = cp abc abc.new
  2. tar xf file.tar.**          不用指定压缩算法,tar自动探测,指定还容易指定错- -!
  3. W命令看当前登录用户,lastb 看最后失败登录。

 

 

[1]http://www.linuxfromscratch.org/hints/downloads/files/OLD/pure_lfs.txt