靈修分享:亞略巴古的演講

亞略巴古的演說是使徒行傳一篇非常著名的講道。基督徒往往用這段經文來說明上帝的屬性,同時也會參考這段經文作為和外邦人互動的一個參考方式。最近因為團契查經查到這一段,重新思想後看到了以前沒有考慮過的面向,在這邊記錄一下。

徒17:16-34保羅在雅典等候他們的時候,看見滿城都是偶像,就心裏着急;於是在會堂裏與猶太人和虔敬的人,並每日在市上所遇見的人,辯論。還有伊壁鳩魯和斯多亞兩門的學士,與他爭論。有的說:「這胡言亂語的要說甚麼?」有的說:「他似乎是傳說外邦鬼神的。」這話是因保羅傳講耶穌與復活的道。他們就把他帶到亞略‧巴古,說:「你所講的這新道,我們也可以知道嗎?因為你有些奇怪的事傳到我們耳中,我們願意知道這些事是甚麼意思。」(雅典人和住在那裏的客人都不顧別的事,只將新聞說說聽聽。)
保羅站在亞略‧巴古當中,說:「眾位雅典人哪,我看你們凡事很敬畏鬼神。我遊行的時候,觀看你們所敬拜的,遇見一座壇,上面寫着『未識之神』。你們所不認識而敬拜的,我現在告訴你們。創造宇宙和其中萬物的神,既是天地的主,就不住人手所造的殿,也不用人手服事,好像缺少甚麼;自己倒將生命、氣息、萬物,賜給萬人。他從一本本:有古卷是血脈造出萬族的人,住在全地上,並且預先定準他們的年限和所住的疆界,要叫他們尋求神,或者可以揣摩而得,其實他離我們各人不遠;我們生活、動作、存留,都在乎他。就如你們作詩的,有人說:『我們也是他所生的。』我們既是神所生的,就不當以為神的神性像人用手藝、心思所雕刻的金、銀、石。世人蒙昧無知的時候,神並不監察,如今卻吩咐各處的人都要悔改。因為他已經定了日子,要藉着他所設立的人按公義審判天下,並且叫他從死裏復活,給萬人作可信的憑據。」
眾人聽見從死裏復活的話,就有譏誚他的;又有人說:「我們再聽你講這個吧!」於是保羅從他們當中出去了。 但有幾個人貼近他,信了主,其中有亞略‧巴古的官丟尼修,並一個婦人,名叫大馬哩,還有別人一同信從。

對基督徒來說,保羅這篇講道講的真好,不但講出了上帝的超越性(像是不住人手所造的殿、也不是金銀石的彫刻),也帶出了耶穌基督復活的大能。但最近我才注意到眾人的反應:「眾人聽見從死裏復活的話,就有譏誚他的;又有人說:「我們再聽你講這個吧!」」不曉得你看到這一段有什麼感想?可能我是玻璃心吧,如果我是保羅,我大概會非常非常的難過,看起來似乎沒有人理會這個福音、這篇講道。這篇被基督…

skb_copy v.s. skb_clone

skb_clone 和 skb_copy 有甚麼不一樣?

從字面上來看,差不多啊,但實際上就是有差,先來看看 Man 吧~

struct sk_buff * skb_clone (struct sk_buff * skb, int gfp_mask);

Duplicate an &sk_buff. The new one is not owned by a socket. Both copies share the same packet data but not structure. The new buffer has a reference count of 1. If the allocation fails the function returns NULL otherwise the new buffer is returned.

If this function is called from an interrupt gfp_mask must be GFP_ATOMIC.

struct sk_buff * skb_copy (const struct sk_buff * skb, int gfp_mask);

Make a copy of both an &sk_buff and its data. This is used when the caller wishes to modify the data and needs a private copy of the data to alter. Returns NULL on failure or the pointer to the buffer on success. The returned buffer has a reference count of 1.

As by-product this function converts non-linear &sk_buff to linear one, so that &sk_buff becomes completely private and caller is allowed to modify all the data of returned buffer. This means that this function is not recommended for use in circumstances when only header is going to be modified. Use pskb_copy instead.

我把最重要的部份用紅色的字體圈出來了~還要更詳細的解釋...恩,直接來看 code 吧。

首先來看 skb_copy

struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
{
....int headerlen = skb->data - skb->head;
..../*
....* Allocate the copy buffer
....*/
....struct sk_buff *n;
#ifdef NET_SKBUFF_DATA_USES_OFFSET
....n = alloc_skb(skb->end + skb->data_len, gfp_mask);
#else
....n = alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask);
#endif
....if (!n)
........return NULL;

..../* Set the data pointer */
....skb_reserve(n, headerlen);
..../* Set the tail pointer and length */
....skb_put(n, skb->len);

....if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len))
........BUG();

....copy_skb_header(n, skb);
....return n;
}

簡單來說,就是先 allocate 一塊 skb_buff 的空間出來,並且根據原來的 skb 進行 空間的設定(包含 skb_reserve, skb_put),最後在進行 data 和 header 拷貝的動作。一些 function 的程式碼列在下面。

/* 在 skb 的前端預留一塊空間 */
static inline void skb_reserve(struct sk_buff *skb, int len)
{
....skb->data += len;
....skb->tail += len;
}

/* 在 skb 的後端預留一塊空間準備填入資料 */
extern unsigned char *skb_put(struct sk_buff *skb, unsigned int len);
static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
{
....unsigned char *tmp = skb_tail_pointer(skb);
....SKB_LINEAR_ASSERT(skb);
....skb->tail += len;
....skb->len += len;
....return tmp;
}

skb_copy_bits 和 copy_skb_header 我就不解釋了。但要特別注意,copy_skb_header 指的是拷貝 skb 這個資料結構的 Header 而不是封包的 Header

下面再來看看 skb_clone:

static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
{
#define C(x) n->x = skb->x

....n->next = n->prev = NULL;
....n->sk = NULL;
....__copy_skb_header(n, skb);

....C(len);
....C(data_len);
....C(mac_len);
....n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
....n->cloned = 1;
....n->nohdr = 0;
....n->destructor = NULL;
....C(iif);
....C(tail);
....C(end);
....C(head);
....C(data);
....C(truesize);
#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
....C(do_not_encrypt);
#endif
....atomic_set(&n->users, 1);

....atomic_inc(&(skb_shinfo(skb)->dataref));
....skb->cloned = 1;

....return n;
#undef C
}

看到了嗎,這過程中,skb_clone 並不會去分配 Data 的記憶體位置,而是直接指定位置到原來的 skb -> data 上面。毫無疑問的,這樣的速度會比較快,但使用上也要更加小心才行。

留言

張貼留言

這個網誌中的熱門文章

如何將Linux打造成OpenFlow Switch:Openvswitch

我弟家的新居感恩禮拜分享:善頌善禱

如何利用 Wireshark 來監聽 IEEE 802.11 的管理封包