2009-06-10 18 views
8

Tôi đang cố gắng thiết lập DF (không phân đoạn cờ) để gửi gói tin bằng UDP.Làm cách nào để đặt cờ không phân đoạn (DF) trên ổ cắm?

Nhìn vào cuốn sách của Richard Steven Tập 1 Lập trình mạng Unix; API mạng ổ cắm, tôi không thể tìm thấy cách thiết lập này.

tôi nghi ngờ rằng tôi sẽ làm điều đó với setsockopt() nhưng không thể tìm thấy nó trong bảng trên trang 193.

Xin gợi ý cách này được thực hiện.

Trả lời

18

Bạn làm điều đó với các setsockopt() cuộc gọi, bằng cách sử dụng tùy chọn IP_DONTFRAG ::

int val = 1; 
setsockopt(sd, IPPROTO_IP, IP_DONTFRAG, &val, sizeof(val)); 

Here's một trang giải thích điều này một cách chi tiết hơn nữa.

Đối với Linux, nó xuất hiện bạn phải sử dụng tùy chọn IP_MTU_DISCOVER với giá trị IP_PMTUDISC_DO (hoặc IP_PMTUDISC_DONT để tắt nó đi):

int val = IP_PMTUDISC_DO; 
setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); 

tôi đã không kiểm tra này, chỉ cần nhìn vào các tập tin header và một chút tìm kiếm trên web, do đó bạn sẽ cần phải kiểm tra nó.

Là để cho dù có một cách khác để cờ DF có thể được thiết lập:

I find nowhere in my program where the "force DF flag" is set, yet tcpdump suggests it is. Is there any other way this could get set?

Từ trang tuyệt vời này here:

IP_MTU_DISCOVER: Sets or receives the Path MTU Discovery setting for a socket. When enabled, Linux will perform Path MTU Discovery as defined in RFC 1191 on this socket. The don't fragment flag is set on all outgoing datagrams. The system-wide default is controlled by the ip_no_pmtu_disc sysctl for SOCK_STREAM sockets, and disabled on all others. For non SOCK_STREAM sockets it is the user's responsibility to packetize the data in MTU sized chunks and to do the retransmits if necessary. The kernel will reject packets that are bigger than the known path MTU if this flag is set (with EMSGSIZE).

này vẻ với tôi như bạn có thể thiết lập mặc định cho toàn hệ thống sử dụng sysctl:

sysctl ip_no_pmtu_disc 

trả về "error: "ip_no_pmtu_disc" is an unknown key" trên hệ thống của tôi nhưng có thể được đặt trên máy của bạn. Ngoài ra, tôi không biết bất cứ điều gì khác (ngoài setsockopt() như đã đề cập trước đây) có thể ảnh hưởng đến cài đặt.

+0

Mà mức là dưới, IPPROTO_IP? – WilliamKF

+0

Có cách nào khác có thể được thiết lập không? Tôi đoán rằng mặc định DF đã tắt, phải không? – WilliamKF

+0

Tôi nghĩ rằng nó là tắt theo mặc định nhưng bạn có thể sử dụng một getockopt (đáng ngạc nhiên đủ :-) để có được giá trị hiện tại của nó. – paxdiablo

3

Nếu bạn đang làm việc trong Userland với ý định bỏ qua ngăn xếp mạng hạt nhân và do đó tạo gói và tiêu đề của riêng bạn và đưa chúng vào mô-đun hạt nhân tùy chỉnh, có một tùy chọn tốt hơn setsockopt().

Bạn thực sự có thể đặt cờ DF giống như bất kỳ trường nào khác của struct iphdr được xác định trong linux/ip.h. Cờ IP 3 bit thực ra là một phần của thành viên frag_off (Phân đoạn bù đắp) của cấu trúc.

Khi bạn nghĩ về điều đó, bạn nên nhóm hai thứ đó thành các cờ có liên quan đến phân mảnh. Theo số RFC-791, phần mô tả cấu trúc tiêu đề IP nói rằng Fragment Offset dài 13 bit và có ba cờ 1 bit. Thành viên frag_off thuộc loại __be16, có thể chứa 13 + 3 bit.

câu chuyện dài ngắn, đây là một giải pháp:

struct iphdr ip; 
ip.frag_off |= ntohs(IP_DF); 

Chúng tôi đang ở đây chính xác thiết lập các bit DF bằng cách sử dụng thiết kế-cho-đó-đặc biệt mục đích IP_DF mặt nạ.

IP_DF được xác định trong net/ip.h (tiêu đề hạt nhân, tất nhiên), trong khi struct iphdr được xác định trong linux/ip.h.

0

Tôi đồng ý với câu trả lời của paxdiablo.

  • setsockopt (sockfd, IPPROTO_IP, IP_MTU_DISCOVER, & val, sizeof (val))
#define IP_PMTUDISC_DONT 0 /* Never send DF frames. */ 
#define IP_PMTUDISC_WANT 1 /* Use per route hints. */ 
#define IP_PMTUDISC_DO  2 /* Always DF. */ 
#define IP_PMTUDISC_PROBE 3 /* Ignore dst pmtu. */ 
  • ip_no_pmtu_disc trong mã nguồn kernel:

if (ipv4_config.no_pmtu_disc) inet->pmtudisc = IP_PMTUDISC_DONT; else inet->pmtudisc = IP_PMTUDISC_WANT;

Các vấn đề liên quan