/*
 * setsockopt ˤե٥λˡ
 *						2002/10/04 kitanim
 */


ե٥ setsockopt(sock, SOL_IPV6, ??? , ...) ƤӽФȤǡꤹ뤳Ȥǽˤʤޤ

ѡ桼¤ɬפޤkernel бƤɬפޤ
include file Ȥ linux/ipv6.h ĥɬפޤ(netinet/in.h ȤĤ֤Ĥޤ)

setsockopt(sock, ***, ...)  ***  SOL_IPV6, IPPROTO_IPV6 ɤǤ⹽ޤ
	#define SOL_IPV6	41	(in linux/socket.h)
	enum {				(in linux/in.h)
	  IPPROTO_IPV6	 = 41,		/* IPv6-in-IPv4 tunnelling		*/
	};

??? ˤϼͤȤޤ
#define	    IPV6_FLOWINFO	11		// ѥåȤ flowlabel ФȤǽˤ롣
#define     IPV6_FLOWLABEL_MGR	32		// in6_flowlabel_req Ȥä flowlabel Ȥ˻ꤹ롣
#define	    IPV6_FLOWINFO_SEND	33		// flowlabel Ĥ롣
#define     IPV6_PKTOPTIONS	6		// TCP ΤȤ˻Ѥ롣

IPV6_FLOWLABEL_MGR Ѥ硢setsockopt ƤӽФ struct in6_flowlabel_req ͤɬפޤ
in6_flowlabel_req ι¤ΤỌ̇̄ϰʲΤȤǤ

struct in6_flowlabel_req
{
	struct in6_addr	flr_dst;		// ե٥դ밸
	__u32	flr_label;			// ե٥
	__u8	flr_action;			// ե٥//
	__u8	flr_share;			// ¾Υץȶͭ뤫
	__u16	flr_flags;			// ٥򿷤뤫ɤ
	__u16 	flr_expires;			// ٥ͭ
	__u16	flr_linger;			// ¾ΰ䥪ץ˺Ѥʤ
	__u32	__flr_pad;
	/* Options in format of IPV6_PKTOPTIONS */
};

// flr_action
#define IPV6_FL_A_GET	0			// Get flow label
#define IPV6_FL_A_PUT	1			// Release flow label
#define IPV6_FL_A_RENEW	2			// Update expire time

// flr_flags
#define IPV6_FL_F_CREATE	1		// Allow to create new label
#define IPV6_FL_F_EXCL		2		// Do not create new label

// flr_share
#define IPV6_FL_S_NONE		0		// Not defined
#define IPV6_FL_S_EXCL		1		// Label is private
#define IPV6_FL_S_PROCESS	2		// May be reused by this process
#define IPV6_FL_S_USER		3		// May be reused by this user
#define IPV6_FL_S_ANY		255		// Anyone may reuse it

ex.
1) ե٥

int set_flowlabel(int sock, struct sockaddr_in6 *dst, __u32 label)
{
	int on = 1;
	struct in6_flowlabel_req freq;

	memset(&freq, 0, sizeof(freq));
	freq.flr_label = htonl(label);
	freq.flr_action = IPV6_FL_A_GET;
	freq.flr_flags = IPV6_FL_F_CREATE | IPV6_FL_F_EXCL;
	freq.flr_share = IPV6_FL_S_EXCL;
	memcpy(&freq.flr_dst, &dst->sin6_addr, 16);
	if (setsockopt(sock, SOL_IPV6, IPV6_FLOWLABEL_MGR, &freq, sizeof(freq)) == -1) {
		perror("can't lease flowlabel");
		return -1;
	}

	dst->sin6_flowinfo = freq.flr_label;		// ʸʤȥե٥뤬ѥåȤˤĤʤ

	if (setsockopt(sock, SOL_IPV6, IPV6_FLOWINFO_SEND, &on, sizeof(on)) == -1) {
		perror("can't send flowinfo");

	// ե٥
		freq.flr_action = IPV6_FL_A_PUT;
		setsockopt(sock, SOL_IPV6, IPV6_FLOWLABEL_MGR, &freq, sizeof(freq));
		return -1;
	}
	return 0;
}

ե٥ꤹݤˤ in6_flowlabel_req ͤŬڤơsetsockopt ƤӽФޤ
 set_flowlabel() ȡsock ˤϥåȤdst ˰ơlabel ˥ե٥ OK Ǥ

ƤӽФ塢顼̵ /proc/net/ip6_flowlabel ˰ʲΤ褦ʥȥ꤬ޤ
( ::1 ΥѥåȤФƥե٥ 9876 Ȥ)
> cat /proc/net/ip6_flowlabel 
Label S Owner  Users  Linger Expires  Dst                              Opt
09876 1 0      0      6      4        00000000000000000000000000000001 0   

Label ϥե٥롢Dst ϰ IPv6 ɥ쥹Ǥ
S  flr_share ͤǾˤä(IPV6_FL_S_ANY ʤ) expire Ʊ٥ꤹ뤳ȤǽǤ
Owner  IPV6_FL_S_USER  uid IPV6_FL_S_PROCESS ȥץID ޤ
Users ϸߤΥ٥ѤƤͿǤ

Linger ϤΥե٥뤬Ǹ˻ȤƤ̵̤ʤޤǤλ(饤ե)ɽޤ
Expires ϥե٥Υ饤եλĤɽѥ桼 0  Expires  0 ˤʤäȤ˥ե٥
ե٥ޥ͡㤬ƤꥹȤޤ
Expires  FL_A_GET  FL_A_RENEW ƤӽФȤ˹ǤޤLinger ͤ꾮ͤǤޤ

setsockopt(sock, SOL_IPV6, IPV6_FLOWLABEL_MGR, ...) ¹Ԥ

dst->sin6_flowinfo = freq.flr_label;

ȤʸѰդʤȥѥåȤ flowlabel ȿǤޤ(sendmsg ϤʳޤǤͤƤСĤǤ⤤Ǥ)
 sendmsg ǰȤϤ sin6  sendmsg  flowlabel ͤ򻲾ȤƤǡ뤫Ǥ

ʸ setsockopt(sock, SOL_IPV6, IPV6_FLOWINFO_SEND, ...) ¹Ԥ sendmsg 򤹤ȡflowlabel ޤ


2) ե٥β

setsockopt(sock, SOL_IPV6, IPV6_FLOWLABEL_MGR, ...) ꤷե٥Ȥˤ
in6_flowlabel_req.flr_action  IPV6_FL_A_PUT ˤ setsockopt(.., IPV6_FLOWLABEL_MGR, ...) ƤӽФ
ޤե٥ IPV6_FL_A_PUT ʳΥѥ᡼ϱƶޤ

IPV6_FL_A_PUT ϥåȤե٥ե٥ޥ͡㤬ե٥ꥹȤ
оݤȤʤե٥Υ桼ΥȤ 1ĸ餷ޤIPV6_FL_S_EXCL ꤷƤ硢
Ʊ٥Ǥꤷ褦Ȥ Operation not permitted ȥ顼Ϥޤ

Linger ̤Ф˻Ȥ褦ˤʤޤip6_flowlabel.c ǺǾͤ 6sec ȷƤޤ(ͤ 60sec)


3) ѥåΥե٥μ

size_t recvlabel(int sock, char *buf, size_t len, int flags, struct sockaddr *addr, int *addrlen)
{
    size_t cc;
    char cbuf[128];
    struct cmsghdr *c;
    struct iovec iov = { buf, len };
    struct msghdr msg = { addr, *addrlen, &iov, 1, cbuf, sizeof(cbuf), 0 };

    cc = recvmsg(sock, &msg, flags);
    if (cc < 0) return cc;
    ((struct sockaddr_in6*)addr)->sin6_flowinfo = 0;
    *addrlen = msg.msg_namelen;
    for (c=CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) {
        if (c->cmsg_level == SOL_IPV6) {
            if (c->cmsg_type == IPV6_FLOWINFO) {
                ((struct sockaddr_in6*)addr)->sin6_flowinfo = *(__u32*)CMSG_DATA(c);
	    }
	}
    }
    return cc;
}

main()
{
  ...

    if (setsockopt(sock, SOL_IPV6, IPV6_FLOWINFO, &on, sizeof(on)) == -1) {	// int on = 1
        perror("can't get flowinfo");
        return -1;
    }

  ...

    len = recvlabel(sock, buff, 128, 0, (struct sockaddr*)&sin6, &sin6_len);
    if (len < 0) {
        perror("recvfrom");
        goto err;
    }
    printf("received flowlabel is 0x%x.\n",ntohl(sin6.sin6_flowinfo));

  ...
}

ѥåȤΥե٥μ recvmsg  CMSG ޥѤ뤳ȤǼǤޤ
recvmsg() ƤӽФ setsockopt(sock, SOL_IPV6, IPV6_FLOWINFO, ...) ƤӽФƤɬפޤ

TCP ξϡsetsockopt(..., IPV6_FLOWINFO, ...) ¹ԤƤ
setsockopt(..., IPV6_PKTOPTIONS, cbuf, &cbuflen) ¹Ԥ recvlabel() ƱͤˡǼǤޤ
cbuf  CMSG Ǽ뤿ΥХåեǤ

ex)
size_t getlabel(int sock, struct sockaddr_in6 *addr, int *addrlen)
{
    size_t cc;
    char cbuf[128];
    struct cmsghdr *c;
    struct msghdr msg = {0};
    int cbuflen;

    cbuflen = sizeof(cbuf);
    msg.msg_control = cbuf;
    msg.msg_controllen = cbuflen;
    cc = getsockopt(sock, SOL_IPV6, IPV6_PKTOPTIONS, cbuf, &cbuflen);
    if (cc < 0) return cc;
    (addr)->sin6_flowinfo = 0;
    *addrlen = cbuflen;
    msg.msg_controllen = cbuflen;
    for (c=CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) {
	if (c->cmsg_level == SOL_IPV6) {
	    if (c->cmsg_type == IPV6_FLOWINFO) {
		(addr)->sin6_flowinfo = *(__u32*)CMSG_DATA(c);
	    }
	}
    }
    return cc;
}

ˡ UDP ǻȤȥơȿˤʤ롣

c.f. getpeername() ϡΥɥ쥹Ȥ갸Υե٥Ǥޤ
	Ĥޤꡢʬդե٥ǧ뤳ȤǤޤ


4) TCP ǤΥե٥ΰ

ե٥򥽥åȤꤹäƤ륷ƥॳ tcp_v6_connect, udpv6_connect, rawv6_sendmsg, udpv6_sendmsg
ʤtcpv6_sendmsg ¸ߤʤ(tcp_sendmsg ѤƤ)ᡢ饤¦ connect Ȥ꤬ǽ
¦ϥե٥򥽥åȤꤹ뤳ȤǤޤ(np->flow_label ؽ񤭹󥹤̵)

ǡsetsockopt(..., IPV6_PKTOPTIONS, ...)  SOCK_STREAM ʬ˰ʲΥѥåƤȲǽˤʤޤ

--- net/ipv6/ipv6_sockglue.c.orig	Tue Jul 16 14:29:31 2002
+++ net/ipv6/ipv6_sockglue.c	Thu Sep 19 12:18:53 2002
@@ -304,6 +304,17 @@
 update:
 		retv = 0;
 		if (sk->type == SOCK_STREAM) {
+			if (np->sndflow && fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+				struct ip6_flowlabel *flowlabel = NULL;
+
+				flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+				if (flowlabel == NULL) {
+					retv = -EINVAL;
+					goto done;
+				}
+				np->flow_label = fl.fl6_flowlabel;
+				fl6_sock_release(flowlabel);
+			}
 			if (opt) {
 				struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 				if (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE))
@@ -457,6 +468,8 @@
 		if (optlen != sizeof(int))
 			goto e_inval;
 		np->sndflow = valbool;
+		if (!valbool && sk->type == SOCK_STREAM)
+			np->flow_label = 0;
 		retv = 0;
 		break;
 	case IPV6_FLOWLABEL_MGR:

(Ȼޤ2002/9/19 ߡԶϤޤ)

 setsockopt Ѥƥե٥ꤹˡʲ˼ޤ

ex)
size_t setlabel(int sock, __u32 flowinfo)
{
    size_t cc;
    char cbuf[128];
    struct cmsghdr *c;
    struct msghdr msg;
    int cbuflen;

    memset(&msg, 0, sizeof(msg));
    memset(cbuf, 0, cbuflen);
    msg.msg_control = cbuf;
    msg.msg_controllen = sizeof(cbuf);
    c = CMSG_FIRSTHDR(&msg);
    c->cmsg_level = SOL_IPV6;
    c->cmsg_type = IPV6_FLOWINFO;
    c->cmsg_len = CMSG_LEN(sizeof(__u32));
    memcpy(CMSG_DATA(c), &flowinfo, sizeof(__u32));
    cbuflen = c->cmsg_len;
    cc = setsockopt(sock, SOL_IPV6, IPV6_PKTOPTIONS, cbuf, cbuflen);
    return cc;
}


<ľ̤Ƥ븽>
Υå(listen 륽å)Ф IPV6_FLOWINFO ꤷ 3)  recvlabel() ¹Ԥ kernel panic ˤʤ롣
TCP ξ硢ѥ뤹륷ü㤦(kterm  rxvt ʤɼब㤦ΤǤϤʤƱ桼 rxvt Ȥ)ǡ
  ե٥Ǥʤ C/S 礬롣
