TL-WR703N is a very tiny router, made by TP-LINK who markets it as “3G travel router”, although without a builtin 3G modem you cannot really say it is a 3G router, which is still an awesome device for its size. Very neat.
There are many stories about how to make it a low power 24x7 downloading box, or a wireless audio streaming box with OpenWrt, I still wanna make it a better router. Since it has only one ethernet interface and has no switch built-in, therefore we often change its role as a normal router with wireless clients to a wireless bridge or repeater with wired clients. It would be cool if the only interface can automatically vary its role according to different situation. To be brief, our goal
is:
When a node’s ethernet wire is plugged in, and makes DHCP requests, the router should assign it a LAN IP.
Otherwise, the router should consider the wire as an WAN path.
Currently, there is a solution to this on the net is to leverage the linux kernel functionality macvlan, and make a virtual interface based on the physical interface with different MAC. This approach just works, but I don’t like the way it shares all the packets of LAN and WAN on the wire without discrimination, and OpenWrt has no uci config for macvlan so far. So I think VLAN trunk is a better way, at least for me. This approach needs configurations on the wired LAN clients, such as Computers and other linux routers. Since the typical applications of mine involve only my own devices, it’s not a big deal.
目前有一种方法可以解决,就是利用 linux kernel 的 macvlan 功能,创建一个基于物理接口的虚拟接口,只是 MAC 不同。这种方法可以工作,不过我不喜欢它对数据包完全不加以区分的方式,并且 OpenWrt 没有专门针对的 macvlan 的配置文件。这种情况下我更倾向于 VLAN trunk。但是这种办法需要在客户端,比如电脑或者其他路由器上进行配置,不过我的典型应用只涉及到我自己的设备,所以这不是什么大问题。
# /etc/config/wireless
config wifi-device 'radio0'
option type 'mac80211'
option macaddr 'xx:xx:xx:xx:xx:xx'
option hwmode '11ng'
option htmode 'HT20'
list ht_capab 'SHORT-GI-20'
list ht_capab 'SHORT-GI-40'
list ht_capab 'RX-STBC1'
list ht_capabb 'DSSS_CCK-40'
option txpower '27'
option country 'US'
option channel '11'
config wifi-iface
option device 'radio0'
option mode 'ap'
option ssid 'OpenWrt'
option encryption 'none'
option network 'lan'
eth0 is WAN, which should work without change; eth0.2 is a VLAN interface created by linux vconfig tagged with ID 2, which is not a hardware VLAN, and eth0.2 is bridged with wireless.
eth0 是 WAN 口,像往常一样不需变动;eth0.2 是 linux vconfig 创建的 VLAN 口, ID 为 2,并非硬件 VLAN,并且 eth0.2 和无线桥接到了一起。
On the client side, the configurations depend on the NIC driver. Most recent intel NICs have VLAN support with official drivers, so do the Realtek ones, but they need additional utility called Windows Diagnostic Program to do this. Here are screen shots:
There are some new operations added to STL containers in C++11, which include emplace, emplace_hint, emplace_front, emplace_after and emplace_back.
Nearly all containers in STL have this kind of operations except std::array, because it’s immutable. All these operations share the common characteristic, which is ‘constructing elements in containers directly without copy or move’.
Motivation
Since C++11 introduced rvalue-reference and its moveable semantic, although a big improvement on performance, sometimes there are still some redundant copy operations. For instance, say we have:
First, the tuple is a POD, therefore no movable constructor, actually it is obvious you cannot move anything from within a POD object. The above code may make some copies of the tuple which depends on the compiler optimaztion.
Second, even when operating on moveable object, some copies still cannot be avoided. You can move a vector, but you still need copy the internal pointer that holds the resource.
Emplace can do better for this, thanks to variadic template and the perfect forwarding. Instead of the above code, we can do:
Here emplace_back will forward all the parameters to some internal function where the vector constructs its elements, just like what a tuple<int, double, long double> t(2, 3.14, 2.71828); does. No copies, no moves, constructs directly.
Another example
1234567
vector<vector<int>>vec_2d;// add a vector filled with five onesvec_2d.push_back(vector<int>(5,1));// using push_back, and expect to movevec_2d.emplace_back(5,1);//or using emplace_back, constructing it directly
Note you only need provide the parameters for the element’s constructor by order.
默认是 memory_order_seq_cst,也就是 sequential-consistent,注意这里说的都是针对 atomic types。因为 C++ 标准不允许 non-atomic 的 data race,包含 data race 的程序视为 undefined behavior(1.10-21)。所以解决潜在的 data race 必须依赖 locks 以及 atomic operation。再强调一下,C++11 中凡是非 atomic type 的 data race 都是未定义行为,程序不可移植,等价于错误的程序。lock 这里不谈,因为使用上是符合直觉以及传统的,目的就是保护好 shared 对象,防止 data race。
Seqential Consistent Ordering
默认的 sequential-consistent model 是沿袭 Java 的内存模型(确切的说是 sequential-consistent with data-race-free),所有的 atomic 操作都可以看作满足唯一 total order 的操作,也就是说,可以把这样的多线程程序理解成一个有先有后交叉运行的单线程程序(对atomic type而言),这在推理时是有帮助的。每个 shared atomic 对象的改变在每个线程看来都是一样的,包括时间顺序以及值。这样一个默认的模型是相对来说符合直觉和容易处理的。举一个 Double-checked locking 的例子。
123456789101112131415161718192021222324
classsingleton{mutablestd::mutexm;mutablestd::atomic<expensive_data*>data;public:// initialize data to 0 in constructor//.....constexpensive_data*get_instance()const{expensive_data*result=data.load();if(!result){std::lock_guard<std::mutex>lk(m);result=data.load();if(!result){result=newexpensive_data;data.store(result);}}returnresult;}};
这里的 load 和 store 默认参数都是memory_order_seq_cst, 等价于调用 data.load(std::memory_order_seq_cst) 和 data.store(result, std::memory_order_seq_cst)。
该语义即同步语义,每一个 acquire 对应一个 release(跨线程的),详细定义参见标准(29.3-2)。需要注意的是 C++ 的同步语义不是先验的,我们无法通过之前的执行判断之后两个操作是否同步了,而只能通过推理所有的情况来验证程序的正确性。具体来说,对于一个可能的 acquire-release pair,我必须考虑他们同步时的情况,也需要考虑他们没有同步时的情况。推理 C++ 多线程程序的正确性,特别是在这两种 ordering 情况下,需要塑模 happens-before 的关系(标准1.10-12),通俗点说,就是推理出相关操作之间所有可能发生的顺序(或者根本就无序)。所以说带锁的多线程的程序很难写正确,更别说无锁的,可见一斑。
举例:
1234567891011
// x0, x1 is atomic bool and initialized to false// victim is atomic int and initialized to 0// Thread 0x0.store(true,memory_order_relaxed);r0=victim.exchange(0,memory_order_acq_rel);r1=x1.load(memory_order_acquire);// Thread 1x1.store(true,memory_order_relaxed);r2=victim.exchange(1,memory_order_acq_rel);r3=x0.load(memory_order_acquire);
你想要快速搭建一个 Nokia 手机可用的 VPN,因为那篇文章采用的是 PSK 认证(pre-shared keys),所以相对来说准备工作和步骤要少很多,实际上会容易一些
你并不需要同时支持其它客户端,比如 iOS,Windows 等等
如果你和笔者一样需要支持手头上的众多设备,那么请继续往下看吧。在本文基础上,可以很容易添加其它的设备。不过请做好心理准备,因为 ipsec 是公认的难搞,再加上 Nokia 设备的极度不友好,所以请一定要有耐心。笔者曾经碰到到相同的配置应用到 Nokia 上,第一次行第二次不行的情况,实在是太诡异了。
......
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
extendedKeyUsage=clientAuth # add or modify this line
......
......
[ server ]
# JY ADDED -- Make a cert with nsCertType set to "server"
basicConstraints=CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
extendedKeyUsage=clientAuth, serverAuth, 1.3.6.1.5.5.8.2.2 # add or modify this line
subjectAltName=DNS:your.vpn.domain # replace with your domain
......
# strongswan.conf - strongSwan configuration file
charon {
# number of worker threads in charon
threads = 16
# send strongswan vendor ID?
# send_vendor_id = yes
dns1 = 8.8.8.8
filelog {
/var/log/charon.log {
# loggers to files also accept the append option to open files in
# append mode at startup (default is yes)
# the default loglevel for all daemon subsystems (defaults to 1).
default = 1
}
stderr {
# more detailed loglevel for a specific subsystem, overriding the
# default loglevel.
ike = 2
knl = 3
}
}
plugins {
sql {
# loglevel to log into sql database
loglevel = -1
# URI to the database
# database = sqlite:///path/to/file.db
# database = mysql://user:password@localhost/database
}
}
}
pluto {
}
libstrongswan {
# set to no, the DH exponent size is optimized
# dh_exponent_ansi_x9_42 = no
}
Nokia Mobile VPN Client,E系列我记得是自带的,其他手机可能要手动下载安装。另外,这里讨论的客户端版本>=3.1,因为3.1之后的客户端支持用一个后缀为 vpn 的 zip 包作为 vpn 策略文件,很方便。之前的版本需要创建 sis 文件,搞不好还要签名。所以这里只考虑3.1以后的。据我所知大都能升级到至少3.1。