Commit 48e24acb authored by David S. Miller's avatar David S. Miller

Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6

into kernel.bkbits.net:/home/davem/net-2.6
parents 0092e993 4f6aeb92
#ifndef _IP6T_REJECT_H
#define _IP6T_REJECT_H
enum ip6t_reject_with {
IP6T_ICMP_NET_UNREACHABLE,
IP6T_ICMP_HOST_UNREACHABLE,
IP6T_ICMP_PROT_UNREACHABLE,
IP6T_ICMP_PORT_UNREACHABLE,
IP6T_ICMP_ECHOREPLY
};
struct ip6t_reject_info {
enum ip6t_reject_with with; /* reject type */
};
#endif /*_IPT_REJECT_H*/
...@@ -134,13 +134,6 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t ...@@ -134,13 +134,6 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t
void netlink_detachskb(struct sock *sk, struct sk_buff *skb); void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol); int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
/* finegrained unicast helpers: */
struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid);
struct sock *netlink_getsockbyfilp(struct file *filp);
int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long timeo);
void netlink_detachskb(struct sock *sk, struct sk_buff *skb);
int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
/* /*
* skb should fit one page. This choice is good for headerless malloc. * skb should fit one page. This choice is good for headerless malloc.
* *
......
...@@ -402,6 +402,16 @@ enum { ...@@ -402,6 +402,16 @@ enum {
#define TCA_ATM_MAX TCA_ATM_STATE #define TCA_ATM_MAX TCA_ATM_STATE
/* Network emulator */ /* Network emulator */
enum
{
TCA_NETEM_UNSPEC,
TCA_NETEM_CORR,
TCA_NETEM_DELAY_DIST,
};
#define TCA_NETEM_MAX TCA_NETEM_DELAY_DIST
struct tc_netem_qopt struct tc_netem_qopt
{ {
__u32 latency; /* added delay (us) */ __u32 latency; /* added delay (us) */
...@@ -411,4 +421,19 @@ struct tc_netem_qopt ...@@ -411,4 +421,19 @@ struct tc_netem_qopt
__u32 duplicate; /* random packet dup (0=none ~0=100%) */ __u32 duplicate; /* random packet dup (0=none ~0=100%) */
__u32 jitter; /* random jitter in latency (us) */ __u32 jitter; /* random jitter in latency (us) */
}; };
struct tc_netem_corr
{
__u32 delay_corr; /* delay correlation */
__u32 loss_corr; /* packet loss correlation */
__u32 dup_corr; /* duplicate correlation */
};
struct tc_netem_dist
{
__u32 size; /* table size */
__u32 factor; /* table scaling factor */
__s16 data[0]; /* distribution table values */
};
#endif #endif
...@@ -106,7 +106,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ...@@ -106,7 +106,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
{ {
char *arpptr = (char *)(arphdr + 1); char *arpptr = (char *)(arphdr + 1);
char *src_devaddr, *tgt_devaddr; char *src_devaddr, *tgt_devaddr;
u32 *src_ipaddr, *tgt_ipaddr; u32 src_ipaddr, tgt_ipaddr;
int i, ret; int i, ret;
#define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg)) #define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg))
...@@ -145,11 +145,11 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ...@@ -145,11 +145,11 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
src_devaddr = arpptr; src_devaddr = arpptr;
arpptr += dev->addr_len; arpptr += dev->addr_len;
src_ipaddr = (u32 *) arpptr; memcpy(&src_ipaddr, arpptr, sizeof(u32));
arpptr += sizeof(u32); arpptr += sizeof(u32);
tgt_devaddr = arpptr; tgt_devaddr = arpptr;
arpptr += dev->addr_len; arpptr += dev->addr_len;
tgt_ipaddr = (u32 *) arpptr; memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len), if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len),
ARPT_INV_SRCDEVADDR) || ARPT_INV_SRCDEVADDR) ||
...@@ -160,19 +160,19 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ...@@ -160,19 +160,19 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
return 0; return 0;
} }
if (FWINV(((*src_ipaddr) & arpinfo->smsk.s_addr) != arpinfo->src.s_addr, if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr,
ARPT_INV_SRCIP) || ARPT_INV_SRCIP) ||
FWINV((((*tgt_ipaddr) & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr), FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr),
ARPT_INV_TGTIP)) { ARPT_INV_TGTIP)) {
dprintf("Source or target IP address mismatch.\n"); dprintf("Source or target IP address mismatch.\n");
dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n", dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
NIPQUAD(*src_ipaddr), NIPQUAD(src_ipaddr),
NIPQUAD(arpinfo->smsk.s_addr), NIPQUAD(arpinfo->smsk.s_addr),
NIPQUAD(arpinfo->src.s_addr), NIPQUAD(arpinfo->src.s_addr),
arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : ""); arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : "");
dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n", dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
NIPQUAD(*tgt_ipaddr), NIPQUAD(tgt_ipaddr),
NIPQUAD(arpinfo->tmsk.s_addr), NIPQUAD(arpinfo->tmsk.s_addr),
NIPQUAD(arpinfo->tgt.s_addr), NIPQUAD(arpinfo->tgt.s_addr),
arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : ""); arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : "");
......
...@@ -38,7 +38,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -38,7 +38,7 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct in6_addr *daddr; struct in6_addr *daddr, *final_p = NULL, final;
struct dst_entry *dst; struct dst_entry *dst;
struct flowi fl; struct flowi fl;
struct ip6_flowlabel *flowlabel = NULL; struct ip6_flowlabel *flowlabel = NULL;
...@@ -157,16 +157,27 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -157,16 +157,27 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (flowlabel) { if (flowlabel) {
if (flowlabel->opt && flowlabel->opt->srcrt) { if (flowlabel->opt && flowlabel->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
} else if (np->opt && np->opt->srcrt) { } else if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) if (err)
goto out; goto out;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
dst_release(dst);
goto out;
}
/* source address lookup done in ip6_dst_lookup */ /* source address lookup done in ip6_dst_lookup */
......
...@@ -796,10 +796,6 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) ...@@ -796,10 +796,6 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
goto out_err_release; goto out_err_release;
} }
} }
if ((err = xfrm_lookup(dst, fl, sk, 0)) < 0) {
err = -ENETUNREACH;
goto out_err_release;
}
return 0; return 0;
......
...@@ -606,7 +606,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -606,7 +606,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
{ {
struct ipv6_txoptions opt_space; struct ipv6_txoptions opt_space;
struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name; struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
struct in6_addr *daddr; struct in6_addr *daddr, *final_p = NULL, final;
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct raw6_opt *raw_opt = raw6_sk(sk); struct raw6_opt *raw_opt = raw6_sk(sk);
...@@ -729,7 +729,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -729,7 +729,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
/* merge ip6_build_xmit from ip6_output */ /* merge ip6_build_xmit from ip6_output */
if (opt && opt->srcrt) { if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
...@@ -738,6 +740,13 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -738,6 +740,13 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) if (err)
goto out; goto out;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
dst_release(dst);
goto out;
}
if (hlimit < 0) { if (hlimit < 0) {
if (ipv6_addr_is_multicast(&fl.fl6_dst)) if (ipv6_addr_is_multicast(&fl.fl6_dst))
......
...@@ -549,7 +549,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -549,7 +549,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_opt *tp = tcp_sk(sk); struct tcp_opt *tp = tcp_sk(sk);
struct in6_addr *saddr = NULL; struct in6_addr *saddr = NULL, *final_p = NULL, final;
struct flowi fl; struct flowi fl;
struct dst_entry *dst; struct dst_entry *dst;
int addr_type; int addr_type;
...@@ -666,13 +666,21 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -666,13 +666,21 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
if (np->opt && np->opt->srcrt) { if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) if (err)
goto failure; goto failure;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
dst_release(dst);
goto failure;
}
if (saddr == NULL) { if (saddr == NULL) {
saddr = &fl.fl6_src; saddr = &fl.fl6_src;
...@@ -793,6 +801,12 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -793,6 +801,12 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
sk->sk_err_soft = -err; sk->sk_err_soft = -err;
goto out; goto out;
} }
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
sk->sk_err_soft = -err;
goto out;
}
} else } else
dst_hold(dst); dst_hold(dst);
...@@ -863,6 +877,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req, ...@@ -863,6 +877,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req,
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff * skb; struct sk_buff * skb;
struct ipv6_txoptions *opt = NULL; struct ipv6_txoptions *opt = NULL;
struct in6_addr * final_p = NULL, final;
struct flowi fl; struct flowi fl;
int err = -1; int err = -1;
...@@ -888,12 +903,18 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req, ...@@ -888,12 +903,18 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req,
if (opt && opt->srcrt) { if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) if (err)
goto done; goto done;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
goto done;
} }
skb = tcp_make_synack(sk, dst, req); skb = tcp_make_synack(sk, dst, req);
...@@ -1021,6 +1042,12 @@ static void tcp_v6_send_reset(struct sk_buff *skb) ...@@ -1021,6 +1042,12 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
/* sk = NULL, but it is safe for now. RST socket required. */ /* sk = NULL, but it is safe for now. RST socket required. */
if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
dst_release(buff->dst);
return;
}
ip6_xmit(NULL, buff, &fl, NULL, 0); ip6_xmit(NULL, buff, &fl, NULL, 0);
TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
...@@ -1082,6 +1109,10 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ...@@ -1082,6 +1109,10 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
fl.fl_ip_sport = t1->source; fl.fl_ip_sport = t1->source;
if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
dst_release(buff->dst);
return;
}
ip6_xmit(NULL, buff, &fl, NULL, 0); ip6_xmit(NULL, buff, &fl, NULL, 0);
TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
return; return;
...@@ -1313,6 +1344,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1313,6 +1344,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
} }
if (dst == NULL) { if (dst == NULL) {
struct in6_addr *final_p = NULL, final;
struct flowi fl; struct flowi fl;
memset(&fl, 0, sizeof(fl)); memset(&fl, 0, sizeof(fl));
...@@ -1320,7 +1352,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1320,7 +1352,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
ipv6_addr_copy(&fl.fl6_dst, &req->af.v6_req.rmt_addr); ipv6_addr_copy(&fl.fl6_dst, &req->af.v6_req.rmt_addr);
if (opt && opt->srcrt) { if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
ipv6_addr_copy(&fl.fl6_src, &req->af.v6_req.loc_addr); ipv6_addr_copy(&fl.fl6_src, &req->af.v6_req.loc_addr);
fl.oif = sk->sk_bound_dev_if; fl.oif = sk->sk_bound_dev_if;
...@@ -1329,6 +1363,12 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1329,6 +1363,12 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
if (ip6_dst_lookup(sk, &dst, &fl)) if (ip6_dst_lookup(sk, &dst, &fl))
goto out; goto out;
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
goto out;
} }
newsk = tcp_create_openreq_child(sk, req, skb); newsk = tcp_create_openreq_child(sk, req, skb);
...@@ -1710,6 +1750,7 @@ static int tcp_v6_rebuild_header(struct sock *sk) ...@@ -1710,6 +1750,7 @@ static int tcp_v6_rebuild_header(struct sock *sk)
if (dst == NULL) { if (dst == NULL) {
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct in6_addr *final_p = NULL, final;
struct flowi fl; struct flowi fl;
memset(&fl, 0, sizeof(fl)); memset(&fl, 0, sizeof(fl));
...@@ -1723,15 +1764,24 @@ static int tcp_v6_rebuild_header(struct sock *sk) ...@@ -1723,15 +1764,24 @@ static int tcp_v6_rebuild_header(struct sock *sk)
if (np->opt && np->opt->srcrt) { if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr); ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
} }
err = ip6_dst_lookup(sk, &dst, &fl); err = ip6_dst_lookup(sk, &dst, &fl);
if (err) { if (err) {
sk->sk_route_caps = 0; sk->sk_route_caps = 0;
return err; return err;
} }
if (final_p)
ipv6_addr_copy(&fl.fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
sk->sk_err_soft = -err;
dst_release(dst);
return err;
}
ip6_dst_store(sk, dst, NULL); ip6_dst_store(sk, dst, NULL);
sk->sk_route_caps = dst->dev->features & sk->sk_route_caps = dst->dev->features &
...@@ -1775,6 +1825,12 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok) ...@@ -1775,6 +1825,12 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
return err; return err;
} }
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
sk->sk_route_caps = 0;
dst_release(dst);
return err;
}
ip6_dst_store(sk, dst, NULL); ip6_dst_store(sk, dst, NULL);
sk->sk_route_caps = dst->dev->features & sk->sk_route_caps = dst->dev->features &
~(NETIF_F_IP_CSUM | NETIF_F_TSO); ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
......
...@@ -627,7 +627,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -627,7 +627,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
struct in6_addr *daddr; struct in6_addr *daddr, *final_p = NULL, final;
struct ipv6_txoptions *opt = NULL; struct ipv6_txoptions *opt = NULL;
struct ip6_flowlabel *flowlabel = NULL; struct ip6_flowlabel *flowlabel = NULL;
struct flowi *fl = &inet->cork.fl; struct flowi *fl = &inet->cork.fl;
...@@ -783,7 +783,9 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -783,7 +783,9 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
/* merge ip6_build_xmit from ip6_output */ /* merge ip6_build_xmit from ip6_output */
if (opt && opt->srcrt) { if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl->fl6_dst);
ipv6_addr_copy(&fl->fl6_dst, rt0->addr); ipv6_addr_copy(&fl->fl6_dst, rt0->addr);
final_p = &final;
} }
if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst))
...@@ -792,6 +794,13 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -792,6 +794,13 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
err = ip6_dst_lookup(sk, &dst, fl); err = ip6_dst_lookup(sk, &dst, fl);
if (err) if (err)
goto out; goto out;
if (final_p)
ipv6_addr_copy(&fl->fl6_dst, final_p);
if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) {
dst_release(dst);
goto out;
}
if (hlimit < 0) { if (hlimit < 0) {
if (ipv6_addr_is_multicast(&fl->fl6_dst)) if (ipv6_addr_is_multicast(&fl->fl6_dst))
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/security.h> #include <linux/security.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/scm.h> #include <net/scm.h>
#include <linux/workqueue.h>
#define Nprintk(a...) #define Nprintk(a...)
...@@ -69,6 +70,14 @@ struct netlink_opt ...@@ -69,6 +70,14 @@ struct netlink_opt
#define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->sk_protinfo) #define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->sk_protinfo)
struct netlink_work
{
struct sock *sk;
int len;
struct work_struct work;
};
static struct workqueue_struct *netlink_wq;
static struct hlist_head nl_table[MAX_LINKS]; static struct hlist_head nl_table[MAX_LINKS];
static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
static unsigned nl_nonroot[MAX_LINKS]; static unsigned nl_nonroot[MAX_LINKS];
...@@ -87,6 +96,16 @@ static atomic_t nl_table_users = ATOMIC_INIT(0); ...@@ -87,6 +96,16 @@ static atomic_t nl_table_users = ATOMIC_INIT(0);
static struct notifier_block *netlink_chain; static struct notifier_block *netlink_chain;
/* netlink workqueue handler */
static void netlink_wq_handler(void *data)
{
struct netlink_work *work = data;
work->sk->sk_data_ready(work->sk, work->len);
sock_put(work->sk);
kfree(work);
}
static void netlink_sock_destruct(struct sock *sk) static void netlink_sock_destruct(struct sock *sk)
{ {
skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_receive_queue);
...@@ -478,6 +497,8 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t ...@@ -478,6 +497,8 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t
if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
test_bit(0, &nlk->state)) { test_bit(0, &nlk->state)) {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
task_t *client;
if (!timeo) { if (!timeo) {
if (!nlk->pid) if (!nlk->pid)
netlink_overrun(sk); netlink_overrun(sk);
...@@ -486,6 +507,19 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t ...@@ -486,6 +507,19 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock, long t
return -EAGAIN; return -EAGAIN;
} }
if (nlk->pid) {
/* Kernel is sending information to user space
* and socket buffer is full: Wake up user
* process */
client = find_task_by_pid(nlk->pid);
if (!client) {
sock_put(sk);
kfree_skb(skb);
return -EAGAIN;
}
wake_up_process(client);
}
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&nlk->wait, &wait); add_wait_queue(&nlk->wait, &wait);
...@@ -525,8 +559,24 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol) ...@@ -525,8 +559,24 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol)
#endif #endif
skb_queue_tail(&sk->sk_receive_queue, skb); skb_queue_tail(&sk->sk_receive_queue, skb);
if (!nlk->pid) {
struct netlink_work *nlwork =
kmalloc(sizeof(struct netlink_work), GFP_KERNEL);
if (!nlwork) {
sock_put(sk);
return -EAGAIN;
}
INIT_WORK(&nlwork->work, netlink_wq_handler, nlwork);
nlwork->sk = sk;
nlwork->len = len;
queue_work(netlink_wq, &nlwork->work);
} else {
sk->sk_data_ready(sk, len); sk->sk_data_ready(sk, len);
sock_put(sk); sock_put(sk);
}
return len; return len;
} }
...@@ -573,7 +623,21 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff ...@@ -573,7 +623,21 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff
skb_orphan(skb); skb_orphan(skb);
skb_set_owner_r(skb, sk); skb_set_owner_r(skb, sk);
skb_queue_tail(&sk->sk_receive_queue, skb); skb_queue_tail(&sk->sk_receive_queue, skb);
if (!nlk->pid) {
struct netlink_work *nlwork =
kmalloc(sizeof(struct netlink_work), GFP_KERNEL);
if (!nlwork)
return -1;
INIT_WORK(&nlwork->work, netlink_wq_handler, nlwork);
nlwork->sk = sk;
nlwork->len = skb->len;
queue_work(netlink_wq, &nlwork->work);
} else
sk->sk_data_ready(sk, skb->len); sk->sk_data_ready(sk, skb->len);
return 0; return 0;
} }
return -1; return -1;
...@@ -619,13 +683,14 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, ...@@ -619,13 +683,14 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
netlink_overrun(sk); netlink_overrun(sk);
/* Clone failed. Notify ALL listeners. */ /* Clone failed. Notify ALL listeners. */
failure = 1; failure = 1;
sock_put(sk);
} else if (netlink_broadcast_deliver(sk, skb2)) { } else if (netlink_broadcast_deliver(sk, skb2)) {
netlink_overrun(sk); netlink_overrun(sk);
sock_put(sk);
} else { } else {
delivered = 1; delivered = 1;
skb2 = NULL; skb2 = NULL;
} }
sock_put(sk);
} }
netlink_unlock_table(); netlink_unlock_table();
...@@ -1202,6 +1267,9 @@ static int __init netlink_proto_init(void) ...@@ -1202,6 +1267,9 @@ static int __init netlink_proto_init(void)
#endif #endif
/* The netlink device handler may be needed early. */ /* The netlink device handler may be needed early. */
rtnetlink_init(); rtnetlink_init();
/* Create a work queue to handle callbacks to modules */
netlink_wq = create_workqueue("netlink");
return 0; return 0;
} }
...@@ -1209,6 +1277,7 @@ static void __exit netlink_proto_exit(void) ...@@ -1209,6 +1277,7 @@ static void __exit netlink_proto_exit(void)
{ {
sock_unregister(PF_NETLINK); sock_unregister(PF_NETLINK);
proc_net_remove("netlink"); proc_net_remove("netlink");
destroy_workqueue(netlink_wq);
} }
core_initcall(netlink_proto_init); core_initcall(netlink_proto_init);
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/io.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/poll.h> #include <linux/poll.h>
...@@ -173,7 +174,7 @@ struct packet_opt ...@@ -173,7 +174,7 @@ struct packet_opt
{ {
struct tpacket_stats stats; struct tpacket_stats stats;
#ifdef CONFIG_PACKET_MMAP #ifdef CONFIG_PACKET_MMAP
unsigned long *pg_vec; char * *pg_vec;
unsigned int head; unsigned int head;
unsigned int frames_per_block; unsigned int frames_per_block;
unsigned int frame_size; unsigned int frame_size;
...@@ -198,15 +199,15 @@ struct packet_opt ...@@ -198,15 +199,15 @@ struct packet_opt
#ifdef CONFIG_PACKET_MMAP #ifdef CONFIG_PACKET_MMAP
static inline unsigned long packet_lookup_frame(struct packet_opt *po, unsigned int position) static inline char *packet_lookup_frame(struct packet_opt *po, unsigned int position)
{ {
unsigned int pg_vec_pos, frame_offset; unsigned int pg_vec_pos, frame_offset;
unsigned long frame; char *frame;
pg_vec_pos = position / po->frames_per_block; pg_vec_pos = position / po->frames_per_block;
frame_offset = position % po->frames_per_block; frame_offset = position % po->frames_per_block;
frame = (unsigned long) (po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size)); frame = po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size);
return frame; return frame;
} }
...@@ -1549,7 +1550,12 @@ static struct vm_operations_struct packet_mmap_ops = { ...@@ -1549,7 +1550,12 @@ static struct vm_operations_struct packet_mmap_ops = {
.close =packet_mm_close, .close =packet_mm_close,
}; };
static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len) static inline struct page *pg_vec_endpage(char *one_pg_vec, unsigned int order)
{
return virt_to_page(one_pg_vec + (PAGE_SIZE << order) - 1);
}
static void free_pg_vec(char **pg_vec, unsigned order, unsigned len)
{ {
int i; int i;
...@@ -1557,10 +1563,10 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len) ...@@ -1557,10 +1563,10 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len)
if (pg_vec[i]) { if (pg_vec[i]) {
struct page *page, *pend; struct page *page, *pend;
pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1); pend = pg_vec_endpage(pg_vec[i], order);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++) for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
ClearPageReserved(page); ClearPageReserved(page);
free_pages(pg_vec[i], order); free_pages((unsigned long)pg_vec[i], order);
} }
} }
kfree(pg_vec); kfree(pg_vec);
...@@ -1569,7 +1575,7 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len) ...@@ -1569,7 +1575,7 @@ static void free_pg_vec(unsigned long *pg_vec, unsigned order, unsigned len)
static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing) static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing)
{ {
unsigned long *pg_vec = NULL; char **pg_vec = NULL;
struct packet_opt *po = pkt_sk(sk); struct packet_opt *po = pkt_sk(sk);
int was_running, num, order = 0; int was_running, num, order = 0;
int err = 0; int err = 0;
...@@ -1604,18 +1610,18 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing ...@@ -1604,18 +1610,18 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
err = -ENOMEM; err = -ENOMEM;
pg_vec = kmalloc(req->tp_block_nr*sizeof(unsigned long*), GFP_KERNEL); pg_vec = kmalloc(req->tp_block_nr*sizeof(char *), GFP_KERNEL);
if (pg_vec == NULL) if (pg_vec == NULL)
goto out; goto out;
memset(pg_vec, 0, req->tp_block_nr*sizeof(unsigned long*)); memset(pg_vec, 0, req->tp_block_nr*sizeof(char **));
for (i=0; i<req->tp_block_nr; i++) { for (i=0; i<req->tp_block_nr; i++) {
struct page *page, *pend; struct page *page, *pend;
pg_vec[i] = __get_free_pages(GFP_KERNEL, order); pg_vec[i] = (char *)__get_free_pages(GFP_KERNEL, order);
if (!pg_vec[i]) if (!pg_vec[i])
goto out_free_pgvec; goto out_free_pgvec;
pend = virt_to_page(pg_vec[i] + (PAGE_SIZE << order) - 1); pend = pg_vec_endpage(pg_vec[i], order);
for (page = virt_to_page(pg_vec[i]); page <= pend; page++) for (page = virt_to_page(pg_vec[i]); page <= pend; page++)
SetPageReserved(page); SetPageReserved(page);
} }
...@@ -1623,7 +1629,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing ...@@ -1623,7 +1629,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
l = 0; l = 0;
for (i=0; i<req->tp_block_nr; i++) { for (i=0; i<req->tp_block_nr; i++) {
unsigned long ptr = pg_vec[i]; char *ptr = pg_vec[i];
struct tpacket_hdr *header; struct tpacket_hdr *header;
int k; int k;
......
...@@ -6,6 +6,9 @@ ...@@ -6,6 +6,9 @@
* as published by the Free Software Foundation; either version * as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
* *
* Many of the algorithms and ideas for this came from
* NIST Net which is not copyrighted.
*
* Authors: Stephen Hemminger <shemminger@osdl.org> * Authors: Stephen Hemminger <shemminger@osdl.org>
* Catalin(ux aka Dino) BOIE <catab at umbrella dot ro> * Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>
*/ */
...@@ -22,11 +25,31 @@ ...@@ -22,11 +25,31 @@
#include <net/pkt_sched.h> #include <net/pkt_sched.h>
/* Network emulator /* Network Emulation Queuing algorithm.
* ====================================
* This scheduler can alters spacing and order
* Similar to NISTnet and BSD Dummynet. Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based
*/ Network Emulation Tool
[2] Luigi Rizzo, DummyNet for FreeBSD
----------------------------------------------------------------
This started out as a simple way to delay outgoing packets to
test TCP but has grown to include most of the functionality
of a full blown network emulator like NISTnet. It can delay
packets and add random jitter (and correlation). The random
distribution can be loaded from a table as well to provide
normal, Pareto, or experimental curves. Packet loss,
duplication, and reordering can also be emulated.
This qdisc does not do classification that can be handled in
layering other disciplines. It does not need to do bandwidth
control either since that can be handled by using token
bucket or other rate control.
The simulator is limited by the Linux timer resolution
and will create packet bursts on the HZ boundary (1ms).
*/
struct netem_sched_data { struct netem_sched_data {
struct Qdisc *qdisc; struct Qdisc *qdisc;
...@@ -39,6 +62,18 @@ struct netem_sched_data { ...@@ -39,6 +62,18 @@ struct netem_sched_data {
u32 counter; u32 counter;
u32 gap; u32 gap;
u32 jitter; u32 jitter;
u32 duplicate;
struct crndstate {
unsigned long last;
unsigned long rho;
} delay_cor, loss_cor, dup_cor;
struct disttable {
u32 size;
u32 factor;
s16 table[0];
} *delay_dist;
}; };
/* Time stamp put into socket buffer control block */ /* Time stamp put into socket buffer control block */
...@@ -46,576 +81,113 @@ struct netem_skb_cb { ...@@ -46,576 +81,113 @@ struct netem_skb_cb {
psched_time_t time_to_send; psched_time_t time_to_send;
}; };
/* This is the distribution table for the normal distribution produced /* init_crandom - initialize correlated random number generator
* with NISTnet tools. * Use entropy source for initial seed.
* The entries represent a scaled inverse of the cumulative distribution
* function.
*/ */
#define TABLESIZE 2048 static void init_crandom(struct crndstate *state, unsigned long rho)
#define TABLEFACTOR 8192 {
state->rho = rho;
static const short disttable[TABLESIZE] = { state->last = net_random();
-31473, -26739, -25226, -24269, }
-23560, -22993, -22518, -22109,
-21749, -21426, -21133, -20865, /* get_crandom - correlated random number generator
-20618, -20389, -20174, -19972, * Next number depends on last value.
-19782, -19601, -19430, -19267, * rho is scaled to avoid floating point.
-19112, -18962, -18819, -18681, */
-18549, -18421, -18298, -18178, static unsigned long get_crandom(struct crndstate *state)
-18062, -17950, -17841, -17735, {
-17632, -17532, -17434, -17339, u64 value, rho;
-17245, -17155, -17066, -16979, unsigned long answer;
-16894, -16811, -16729, -16649,
-16571, -16494, -16419, -16345, if (state->rho == 0) /* no correllation */
-16272, -16201, -16130, -16061, return net_random();
-15993, -15926, -15861, -15796,
-15732, -15669, -15607, -15546, value = net_random();
-15486, -15426, -15368, -15310, rho = (u64)state->rho + 1;
-15253, -15196, -15140, -15086, answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
-15031, -14977, -14925, -14872, state->last = answer;
-14821, -14769, -14719, -14669, return answer;
-14619, -14570, -14522, -14473, }
-14426, -14379, -14332, -14286,
-14241, -14196, -14150, -14106,
-14062, -14019, -13976, -13933,
-13890, -13848, -13807, -13765,
-13724, -13684, -13643, -13604,
-13564, -13525, -13486, -13447,
-13408, -13370, -13332, -13295,
-13258, -13221, -13184, -13147,
-13111, -13075, -13040, -13004,
-12969, -12934, -12899, -12865,
-12830, -12796, -12762, -12729,
-12695, -12662, -12629, -12596,
-12564, -12531, -12499, -12467,
-12435, -12404, -12372, -12341,
-12310, -12279, -12248, -12218,
-12187, -12157, -12127, -12097,
-12067, -12038, -12008, -11979,
-11950, -11921, -11892, -11863,
-11835, -11806, -11778, -11750,
-11722, -11694, -11666, -11639,
-11611, -11584, -11557, -11530,
-11503, -11476, -11450, -11423,
-11396, -11370, -11344, -11318,
-11292, -11266, -11240, -11214,
-11189, -11164, -11138, -11113,
-11088, -11063, -11038, -11013,
-10988, -10964, -10939, -10915,
-10891, -10866, -10843, -10818,
-10794, -10770, -10747, -10723,
-10700, -10676, -10652, -10630,
-10606, -10583, -10560, -10537,
-10514, -10491, -10469, -10446,
-10424, -10401, -10378, -10356,
-10334, -10312, -10290, -10267,
-10246, -10224, -10202, -10180,
-10158, -10137, -10115, -10094,
-10072, -10051, -10030, -10009,
-9988, -9967, -9945, -9925,
-9904, -9883, -9862, -9842,
-9821, -9800, -9780, -9760,
-9739, -9719, -9699, -9678,
-9658, -9638, -9618, -9599,
-9578, -9559, -9539, -9519,
-9499, -9480, -9461, -9441,
-9422, -9402, -9383, -9363,
-9344, -9325, -9306, -9287,
-9268, -9249, -9230, -9211,
-9192, -9173, -9155, -9136,
-9117, -9098, -9080, -9062,
-9043, -9025, -9006, -8988,
-8970, -8951, -8933, -8915,
-8897, -8879, -8861, -8843,
-8825, -8807, -8789, -8772,
-8754, -8736, -8718, -8701,
-8683, -8665, -8648, -8630,
-8613, -8595, -8578, -8561,
-8543, -8526, -8509, -8492,
-8475, -8458, -8441, -8423,
-8407, -8390, -8373, -8356,
-8339, -8322, -8305, -8289,
-8272, -8255, -8239, -8222,
-8206, -8189, -8172, -8156,
-8140, -8123, -8107, -8090,
-8074, -8058, -8042, -8025,
-8009, -7993, -7977, -7961,
-7945, -7929, -7913, -7897,
-7881, -7865, -7849, -7833,
-7817, -7802, -7786, -7770,
-7754, -7739, -7723, -7707,
-7692, -7676, -7661, -7645,
-7630, -7614, -7599, -7583,
-7568, -7553, -7537, -7522,
-7507, -7492, -7476, -7461,
-7446, -7431, -7416, -7401,
-7385, -7370, -7356, -7340,
-7325, -7311, -7296, -7281,
-7266, -7251, -7236, -7221,
-7207, -7192, -7177, -7162,
-7148, -7133, -7118, -7104,
-7089, -7075, -7060, -7046,
-7031, -7016, -7002, -6988,
-6973, -6959, -6944, -6930,
-6916, -6901, -6887, -6873,
-6859, -6844, -6830, -6816,
-6802, -6788, -6774, -6760,
-6746, -6731, -6717, -6704,
-6690, -6675, -6661, -6647,
-6633, -6620, -6606, -6592,
-6578, -6564, -6550, -6537,
-6523, -6509, -6495, -6482,
-6468, -6454, -6441, -6427,
-6413, -6400, -6386, -6373,
-6359, -6346, -6332, -6318,
-6305, -6291, -6278, -6264,
-6251, -6238, -6224, -6211,
-6198, -6184, -6171, -6158,
-6144, -6131, -6118, -6105,
-6091, -6078, -6065, -6052,
-6039, -6025, -6012, -5999,
-5986, -5973, -5960, -5947,
-5934, -5921, -5908, -5895,
-5882, -5869, -5856, -5843,
-5830, -5817, -5804, -5791,
-5779, -5766, -5753, -5740,
-5727, -5714, -5702, -5689,
-5676, -5663, -5650, -5638,
-5625, -5612, -5600, -5587,
-5575, -5562, -5549, -5537,
-5524, -5512, -5499, -5486,
-5474, -5461, -5449, -5436,
-5424, -5411, -5399, -5386,
-5374, -5362, -5349, -5337,
-5324, -5312, -5299, -5287,
-5275, -5263, -5250, -5238,
-5226, -5213, -5201, -5189,
-5177, -5164, -5152, -5140,
-5128, -5115, -5103, -5091,
-5079, -5067, -5055, -5043,
-5030, -5018, -5006, -4994,
-4982, -4970, -4958, -4946,
-4934, -4922, -4910, -4898,
-4886, -4874, -4862, -4850,
-4838, -4826, -4814, -4803,
-4791, -4778, -4767, -4755,
-4743, -4731, -4719, -4708,
-4696, -4684, -4672, -4660,
-4649, -4637, -4625, -4613,
-4601, -4590, -4578, -4566,
-4554, -4543, -4531, -4520,
-4508, -4496, -4484, -4473,
-4461, -4449, -4438, -4427,
-4415, -4403, -4392, -4380,
-4368, -4357, -4345, -4334,
-4322, -4311, -4299, -4288,
-4276, -4265, -4253, -4242,
-4230, -4219, -4207, -4196,
-4184, -4173, -4162, -4150,
-4139, -4128, -4116, -4105,
-4094, -4082, -4071, -4060,
-4048, -4037, -4026, -4014,
-4003, -3992, -3980, -3969,
-3958, -3946, -3935, -3924,
-3913, -3901, -3890, -3879,
-3868, -3857, -3845, -3834,
-3823, -3812, -3801, -3790,
-3779, -3767, -3756, -3745,
-3734, -3723, -3712, -3700,
-3689, -3678, -3667, -3656,
-3645, -3634, -3623, -3612,
-3601, -3590, -3579, -3568,
-3557, -3545, -3535, -3524,
-3513, -3502, -3491, -3480,
-3469, -3458, -3447, -3436,
-3425, -3414, -3403, -3392,
-3381, -3370, -3360, -3348,
-3337, -3327, -3316, -3305,
-3294, -3283, -3272, -3262,
-3251, -3240, -3229, -3218,
-3207, -3197, -3185, -3175,
-3164, -3153, -3142, -3132,
-3121, -3110, -3099, -3088,
-3078, -3067, -3056, -3045,
-3035, -3024, -3013, -3003,
-2992, -2981, -2970, -2960,
-2949, -2938, -2928, -2917,
-2906, -2895, -2885, -2874,
-2864, -2853, -2842, -2832,
-2821, -2810, -2800, -2789,
-2778, -2768, -2757, -2747,
-2736, -2725, -2715, -2704,
-2694, -2683, -2673, -2662,
-2651, -2641, -2630, -2620,
-2609, -2599, -2588, -2578,
-2567, -2556, -2546, -2535,
-2525, -2515, -2504, -2493,
-2483, -2472, -2462, -2451,
-2441, -2431, -2420, -2410,
-2399, -2389, -2378, -2367,
-2357, -2347, -2336, -2326,
-2315, -2305, -2295, -2284,
-2274, -2263, -2253, -2243,
-2232, -2222, -2211, -2201,
-2191, -2180, -2170, -2159,
-2149, -2139, -2128, -2118,
-2107, -2097, -2087, -2076,
-2066, -2056, -2046, -2035,
-2025, -2014, -2004, -1994,
-1983, -1973, -1963, -1953,
-1942, -1932, -1921, -1911,
-1901, -1891, -1880, -1870,
-1860, -1849, -1839, -1829,
-1819, -1808, -1798, -1788,
-1778, -1767, -1757, -1747,
-1736, -1726, -1716, -1706,
-1695, -1685, -1675, -1665,
-1654, -1644, -1634, -1624,
-1613, -1603, -1593, -1583,
-1573, -1563, -1552, -1542,
-1532, -1522, -1511, -1501,
-1491, -1481, -1471, -1461,
-1450, -1440, -1430, -1420,
-1409, -1400, -1389, -1379,
-1369, -1359, -1348, -1339,
-1328, -1318, -1308, -1298,
-1288, -1278, -1267, -1257,
-1247, -1237, -1227, -1217,
-1207, -1196, -1186, -1176,
-1166, -1156, -1146, -1135,
-1126, -1115, -1105, -1095,
-1085, -1075, -1065, -1055,
-1044, -1034, -1024, -1014,
-1004, -994, -984, -974,
-964, -954, -944, -933,
-923, -913, -903, -893,
-883, -873, -863, -853,
-843, -833, -822, -812,
-802, -792, -782, -772,
-762, -752, -742, -732,
-722, -712, -702, -691,
-682, -671, -662, -651,
-641, -631, -621, -611,
-601, -591, -581, -571,
-561, -551, -541, -531,
-521, -511, -501, -491,
-480, -471, -460, -451,
-440, -430, -420, -410,
-400, -390, -380, -370,
-360, -350, -340, -330,
-320, -310, -300, -290,
-280, -270, -260, -250,
-240, -230, -220, -210,
-199, -190, -179, -170,
-159, -150, -139, -129,
-119, -109, -99, -89,
-79, -69, -59, -49,
-39, -29, -19, -9,
1, 11, 21, 31,
41, 51, 61, 71,
81, 91, 101, 111,
121, 131, 141, 152,
161, 172, 181, 192,
202, 212, 222, 232,
242, 252, 262, 272,
282, 292, 302, 312,
322, 332, 342, 352,
362, 372, 382, 392,
402, 412, 422, 433,
442, 453, 462, 473,
483, 493, 503, 513,
523, 533, 543, 553,
563, 573, 583, 593,
603, 613, 623, 633,
643, 653, 664, 673,
684, 694, 704, 714,
724, 734, 744, 754,
764, 774, 784, 794,
804, 815, 825, 835,
845, 855, 865, 875,
885, 895, 905, 915,
925, 936, 946, 956,
966, 976, 986, 996,
1006, 1016, 1026, 1037,
1047, 1057, 1067, 1077,
1087, 1097, 1107, 1117,
1128, 1138, 1148, 1158,
1168, 1178, 1188, 1198,
1209, 1219, 1229, 1239,
1249, 1259, 1269, 1280,
1290, 1300, 1310, 1320,
1330, 1341, 1351, 1361,
1371, 1381, 1391, 1402,
1412, 1422, 1432, 1442,
1452, 1463, 1473, 1483,
1493, 1503, 1513, 1524,
1534, 1544, 1554, 1565,
1575, 1585, 1595, 1606,
1616, 1626, 1636, 1647,
1656, 1667, 1677, 1687,
1697, 1708, 1718, 1729,
1739, 1749, 1759, 1769,
1780, 1790, 1800, 1810,
1821, 1831, 1841, 1851,
1862, 1872, 1883, 1893,
1903, 1913, 1923, 1934,
1944, 1955, 1965, 1975,
1985, 1996, 2006, 2016,
2027, 2037, 2048, 2058,
2068, 2079, 2089, 2099,
2110, 2120, 2130, 2141,
2151, 2161, 2172, 2182,
2193, 2203, 2213, 2224,
2234, 2245, 2255, 2265,
2276, 2286, 2297, 2307,
2318, 2328, 2338, 2349,
2359, 2370, 2380, 2391,
2401, 2412, 2422, 2433,
2443, 2454, 2464, 2475,
2485, 2496, 2506, 2517,
2527, 2537, 2548, 2559,
2569, 2580, 2590, 2601,
2612, 2622, 2632, 2643,
2654, 2664, 2675, 2685,
2696, 2707, 2717, 2728,
2738, 2749, 2759, 2770,
2781, 2791, 2802, 2813,
2823, 2834, 2845, 2855,
2866, 2877, 2887, 2898,
2909, 2919, 2930, 2941,
2951, 2962, 2973, 2984,
2994, 3005, 3015, 3027,
3037, 3048, 3058, 3069,
3080, 3091, 3101, 3113,
3123, 3134, 3145, 3156,
3166, 3177, 3188, 3199,
3210, 3220, 3231, 3242,
3253, 3264, 3275, 3285,
3296, 3307, 3318, 3329,
3340, 3351, 3362, 3373,
3384, 3394, 3405, 3416,
3427, 3438, 3449, 3460,
3471, 3482, 3493, 3504,
3515, 3526, 3537, 3548,
3559, 3570, 3581, 3592,
3603, 3614, 3625, 3636,
3647, 3659, 3670, 3681,
3692, 3703, 3714, 3725,
3736, 3747, 3758, 3770,
3781, 3792, 3803, 3814,
3825, 3837, 3848, 3859,
3870, 3881, 3893, 3904,
3915, 3926, 3937, 3949,
3960, 3971, 3983, 3994,
4005, 4017, 4028, 4039,
4051, 4062, 4073, 4085,
4096, 4107, 4119, 4130,
4141, 4153, 4164, 4175,
4187, 4198, 4210, 4221,
4233, 4244, 4256, 4267,
4279, 4290, 4302, 4313,
4325, 4336, 4348, 4359,
4371, 4382, 4394, 4406,
4417, 4429, 4440, 4452,
4464, 4475, 4487, 4499,
4510, 4522, 4533, 4545,
4557, 4569, 4581, 4592,
4604, 4616, 4627, 4639,
4651, 4663, 4674, 4686,
4698, 4710, 4722, 4734,
4746, 4758, 4769, 4781,
4793, 4805, 4817, 4829,
4841, 4853, 4865, 4877,
4889, 4900, 4913, 4925,
4936, 4949, 4961, 4973,
4985, 4997, 5009, 5021,
5033, 5045, 5057, 5070,
5081, 5094, 5106, 5118,
5130, 5143, 5155, 5167,
5179, 5191, 5204, 5216,
5228, 5240, 5253, 5265,
5278, 5290, 5302, 5315,
5327, 5340, 5352, 5364,
5377, 5389, 5401, 5414,
5426, 5439, 5451, 5464,
5476, 5489, 5502, 5514,
5527, 5539, 5552, 5564,
5577, 5590, 5603, 5615,
5628, 5641, 5653, 5666,
5679, 5691, 5704, 5717,
5730, 5743, 5756, 5768,
5781, 5794, 5807, 5820,
5833, 5846, 5859, 5872,
5885, 5897, 5911, 5924,
5937, 5950, 5963, 5976,
5989, 6002, 6015, 6028,
6042, 6055, 6068, 6081,
6094, 6108, 6121, 6134,
6147, 6160, 6174, 6187,
6201, 6214, 6227, 6241,
6254, 6267, 6281, 6294,
6308, 6321, 6335, 6348,
6362, 6375, 6389, 6403,
6416, 6430, 6443, 6457,
6471, 6485, 6498, 6512,
6526, 6540, 6554, 6567,
6581, 6595, 6609, 6623,
6637, 6651, 6665, 6679,
6692, 6706, 6721, 6735,
6749, 6763, 6777, 6791,
6805, 6819, 6833, 6848,
6862, 6876, 6890, 6905,
6919, 6933, 6948, 6962,
6976, 6991, 7005, 7020,
7034, 7049, 7064, 7078,
7093, 7107, 7122, 7136,
7151, 7166, 7180, 7195,
7210, 7225, 7240, 7254,
7269, 7284, 7299, 7314,
7329, 7344, 7359, 7374,
7389, 7404, 7419, 7434,
7449, 7465, 7480, 7495,
7510, 7526, 7541, 7556,
7571, 7587, 7602, 7618,
7633, 7648, 7664, 7680,
7695, 7711, 7726, 7742,
7758, 7773, 7789, 7805,
7821, 7836, 7852, 7868,
7884, 7900, 7916, 7932,
7948, 7964, 7981, 7997,
8013, 8029, 8045, 8061,
8078, 8094, 8110, 8127,
8143, 8160, 8176, 8193,
8209, 8226, 8242, 8259,
8276, 8292, 8309, 8326,
8343, 8360, 8377, 8394,
8410, 8428, 8444, 8462,
8479, 8496, 8513, 8530,
8548, 8565, 8582, 8600,
8617, 8634, 8652, 8670,
8687, 8704, 8722, 8740,
8758, 8775, 8793, 8811,
8829, 8847, 8865, 8883,
8901, 8919, 8937, 8955,
8974, 8992, 9010, 9029,
9047, 9066, 9084, 9103,
9121, 9140, 9159, 9177,
9196, 9215, 9234, 9253,
9272, 9291, 9310, 9329,
9349, 9368, 9387, 9406,
9426, 9445, 9465, 9484,
9504, 9524, 9544, 9563,
9583, 9603, 9623, 9643,
9663, 9683, 9703, 9723,
9744, 9764, 9785, 9805,
9826, 9846, 9867, 9888,
9909, 9930, 9950, 9971,
9993, 10013, 10035, 10056,
10077, 10099, 10120, 10142,
10163, 10185, 10207, 10229,
10251, 10273, 10294, 10317,
10339, 10361, 10384, 10406,
10428, 10451, 10474, 10496,
10519, 10542, 10565, 10588,
10612, 10635, 10658, 10682,
10705, 10729, 10752, 10776,
10800, 10824, 10848, 10872,
10896, 10921, 10945, 10969,
10994, 11019, 11044, 11069,
11094, 11119, 11144, 11169,
11195, 11221, 11246, 11272,
11298, 11324, 11350, 11376,
11402, 11429, 11456, 11482,
11509, 11536, 11563, 11590,
11618, 11645, 11673, 11701,
11728, 11756, 11785, 11813,
11842, 11870, 11899, 11928,
11957, 11986, 12015, 12045,
12074, 12104, 12134, 12164,
12194, 12225, 12255, 12286,
12317, 12348, 12380, 12411,
12443, 12475, 12507, 12539,
12571, 12604, 12637, 12670,
12703, 12737, 12771, 12804,
12839, 12873, 12907, 12942,
12977, 13013, 13048, 13084,
13120, 13156, 13192, 13229,
13267, 13304, 13341, 13379,
13418, 13456, 13495, 13534,
13573, 13613, 13653, 13693,
13734, 13775, 13817, 13858,
13901, 13943, 13986, 14029,
14073, 14117, 14162, 14206,
14252, 14297, 14343, 14390,
14437, 14485, 14533, 14582,
14631, 14680, 14731, 14782,
14833, 14885, 14937, 14991,
15044, 15099, 15154, 15210,
15266, 15324, 15382, 15441,
15500, 15561, 15622, 15684,
15747, 15811, 15877, 15943,
16010, 16078, 16148, 16218,
16290, 16363, 16437, 16513,
16590, 16669, 16749, 16831,
16915, 17000, 17088, 17177,
17268, 17362, 17458, 17556,
17657, 17761, 17868, 17977,
18090, 18207, 18328, 18452,
18581, 18715, 18854, 18998,
19149, 19307, 19472, 19645,
19828, 20021, 20226, 20444,
20678, 20930, 21204, 21503,
21835, 22206, 22630, 23124,
23721, 24478, 25529, 27316,
};
/* tabledist - return a pseudo-randomly distributed value with mean mu and /* tabledist - return a pseudo-randomly distributed value with mean mu and
* std deviation sigma. Uses table lookup to approximate the desired * std deviation sigma. Uses table lookup to approximate the desired
* distribution, and a uniformly-distributed pseudo-random source. * distribution, and a uniformly-distributed pseudo-random source.
*/ */
static inline int tabledist(int mu, int sigma) static unsigned long tabledist(int mu, int sigma,
struct crndstate *state,
const struct disttable *dist)
{ {
int x; int t, x, factor;
int index; unsigned long rnd;
int sigmamod, sigmadiv;
if (sigma == 0) if (sigma == 0)
return mu; return mu;
index = (net_random() & (TABLESIZE-1)); rnd = get_crandom(state);
sigmamod = sigma%TABLEFACTOR;
sigmadiv = sigma/TABLEFACTOR; /* default uniform distribution */
x = sigmamod*disttable[index]; if (dist == NULL)
return (rnd % (2*sigma)) - sigma + mu;
factor = dist->factor;
t = dist->table[rnd % dist->size];
x = (sigma % factor) * t;
if (x >= 0) if (x >= 0)
x += TABLEFACTOR/2; x += factor/2;
else else
x -= TABLEFACTOR/2; x -= factor/2;
x /= TABLEFACTOR; return (x + (sigma / factor) * t) / factor + mu;
x += sigmadiv*disttable[index];
x += mu;
return x;
} }
/* Enqueue packets with underlying discipline (fifo) /* Put skb in the private delayed queue. */
* but mark them with current time first. static int delay_skb(struct Qdisc *sch, struct sk_buff *skb)
*/
static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{ {
struct netem_sched_data *q = qdisc_priv(sch); struct netem_sched_data *q = qdisc_priv(sch);
struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb; struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;
psched_time_t now; psched_time_t now;
long delay;
PSCHED_GET_TIME(now);
PSCHED_TADD2(now, tabledist(q->latency, q->jitter,
&q->delay_cor, q->delay_dist),
cb->time_to_send);
/* Always queue at tail to keep packets in order */
if (likely(q->delayed.qlen < q->limit)) {
__skb_queue_tail(&q->delayed, skb);
sch->q.qlen++;
sch->stats.bytes += skb->len;
sch->stats.packets++;
return NET_XMIT_SUCCESS;
}
sch->stats.drops++;
kfree_skb(skb);
return NET_XMIT_DROP;
}
static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
struct netem_sched_data *q = qdisc_priv(sch);
pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies); pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies);
/* Random packet drop 0 => none, ~0 => all */ /* Random packet drop 0 => none, ~0 => all */
if (q->loss && q->loss >= net_random()) { if (q->loss && q->loss >= get_crandom(&q->loss_cor)) {
pr_debug("netem_enqueue: random loss\n");
sch->stats.drops++; sch->stats.drops++;
return 0; /* lie about loss so TCP doesn't know */ return 0; /* lie about loss so TCP doesn't know */
} }
/* Random duplication */
if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
pr_debug("netem_enqueue: dup %p\n", skb2);
if (skb2)
delay_skb(sch, skb2);
}
/* If doing simple delay then gap == 0 so all packets /* If doing simple delay then gap == 0 so all packets
* go into the delayed holding queue * go into the delayed holding queue
...@@ -634,26 +206,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) ...@@ -634,26 +206,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
q->counter = 0; q->counter = 0;
PSCHED_GET_TIME(now); return delay_skb(sch, skb);
if (q->jitter)
delay = tabledist(q->latency, q->jitter);
else
delay = q->latency;
PSCHED_TADD2(now, delay, cb->time_to_send);
/* Always queue at tail to keep packets in order */
if (likely(q->delayed.qlen < q->limit)) {
__skb_queue_tail(&q->delayed, skb);
sch->q.qlen++;
sch->stats.bytes += skb->len;
sch->stats.packets++;
return 0;
}
sch->stats.drops++;
kfree_skb(skb);
return NET_XMIT_DROP;
} }
/* Requeue packets but don't change time stamp */ /* Requeue packets but don't change time stamp */
...@@ -752,39 +305,94 @@ static int set_fifo_limit(struct Qdisc *q, int limit) ...@@ -752,39 +305,94 @@ static int set_fifo_limit(struct Qdisc *q, int limit)
return ret; return ret;
} }
static int netem_change(struct Qdisc *sch, struct rtattr *opt) static int get_dist_table(struct Qdisc *sch, const struct rtattr *attr)
{ {
struct netem_sched_data *q = qdisc_priv(sch); struct netem_sched_data *q = qdisc_priv(sch);
struct tc_netem_qopt *qopt = RTA_DATA(opt); const struct tc_netem_dist *dist = RTA_DATA(attr);
struct Qdisc *child; struct disttable *d;
int ret; int i;
if (RTA_PAYLOAD(attr) < sizeof(*dist) ||
dist->factor < 2 || dist->factor > 1<<16 || dist->size > 65536)
return -EINVAL;
d = kmalloc(sizeof(*d) + dist->size*sizeof(d->table[0]), GFP_KERNEL);
if (!d)
return -ENOMEM;
d->size = dist->size;
d->factor = dist->factor;
for (i = 0; i < dist->size; i++)
d->table[i] = dist->data[i];
spin_lock_bh(&sch->dev->queue_lock);
d = xchg(&q->delay_dist, d);
spin_unlock_bh(&sch->dev->queue_lock);
kfree(d);
return 0;
}
if (opt->rta_len < RTA_LENGTH(sizeof(*qopt))) static int get_correlation(struct Qdisc *sch, const struct rtattr *attr)
{
struct netem_sched_data *q = qdisc_priv(sch);
const struct tc_netem_corr *c = RTA_DATA(attr);
if (RTA_PAYLOAD(attr) != sizeof(*c))
return -EINVAL; return -EINVAL;
child = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); init_crandom(&q->delay_cor, c->delay_corr);
if (!child) init_crandom(&q->loss_cor, c->loss_corr);
init_crandom(&q->dup_cor, c->dup_corr);
return 0;
}
static int netem_change(struct Qdisc *sch, struct rtattr *opt)
{
struct netem_sched_data *q = qdisc_priv(sch);
struct tc_netem_qopt *qopt;
int ret;
if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt))
return -EINVAL; return -EINVAL;
ret = set_fifo_limit(child, qopt->limit); qopt = RTA_DATA(opt);
ret = set_fifo_limit(q->qdisc, qopt->limit);
if (ret) { if (ret) {
qdisc_destroy(child); pr_debug("netem: can't set fifo limit\n");
return ret; return ret;
} }
sch_tree_lock(sch);
if (child) {
child = xchg(&q->qdisc, child);
if (child != &noop_qdisc)
qdisc_destroy(child);
q->latency = qopt->latency; q->latency = qopt->latency;
q->jitter = qopt->jitter; q->jitter = qopt->jitter;
q->limit = qopt->limit; q->limit = qopt->limit;
q->gap = qopt->gap; q->gap = qopt->gap;
q->loss = qopt->loss; q->loss = qopt->loss;
q->duplicate = qopt->duplicate;
/* Handle nested options after initial queue options.
* Should have put all options in nested format but too late now.
*/
if (RTA_PAYLOAD(opt) > sizeof(*qopt)) {
struct rtattr *tb[TCA_NETEM_MAX];
if (rtattr_parse(tb, TCA_NETEM_MAX,
RTA_DATA(opt) + sizeof(*qopt),
RTA_PAYLOAD(opt) - sizeof(*qopt)))
return -EINVAL;
if (tb[TCA_NETEM_CORR-1]) {
ret = get_correlation(sch, tb[TCA_NETEM_CORR-1]);
if (ret)
return ret;
} }
sch_tree_unlock(sch);
if (tb[TCA_NETEM_DELAY_DIST-1]) {
ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST-1]);
if (ret)
return ret;
}
}
return 0; return 0;
} }
...@@ -792,19 +400,29 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt) ...@@ -792,19 +400,29 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt)
static int netem_init(struct Qdisc *sch, struct rtattr *opt) static int netem_init(struct Qdisc *sch, struct rtattr *opt)
{ {
struct netem_sched_data *q = qdisc_priv(sch); struct netem_sched_data *q = qdisc_priv(sch);
int ret;
if (!opt) if (!opt)
return -EINVAL; return -EINVAL;
skb_queue_head_init(&q->delayed); skb_queue_head_init(&q->delayed);
q->qdisc = &noop_qdisc;
init_timer(&q->timer); init_timer(&q->timer);
q->timer.function = netem_watchdog; q->timer.function = netem_watchdog;
q->timer.data = (unsigned long) sch; q->timer.data = (unsigned long) sch;
q->counter = 0; q->counter = 0;
return netem_change(sch, opt); q->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
if (!q->qdisc) {
pr_debug("netem: qdisc create failed\n");
return -ENOMEM;
}
ret = netem_change(sch, opt);
if (ret) {
pr_debug("netem: change failed\n");
qdisc_destroy(q->qdisc);
}
return ret;
} }
static void netem_destroy(struct Qdisc *sch) static void netem_destroy(struct Qdisc *sch)
...@@ -817,18 +435,26 @@ static void netem_destroy(struct Qdisc *sch) ...@@ -817,18 +435,26 @@ static void netem_destroy(struct Qdisc *sch)
static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
{ {
struct netem_sched_data *q = qdisc_priv(sch); const struct netem_sched_data *q = qdisc_priv(sch);
unsigned char *b = skb->tail; unsigned char *b = skb->tail;
struct rtattr *rta = (struct rtattr *) b;
struct tc_netem_qopt qopt; struct tc_netem_qopt qopt;
struct tc_netem_corr cor;
qopt.latency = q->latency; qopt.latency = q->latency;
qopt.jitter = q->jitter; qopt.jitter = q->jitter;
qopt.limit = q->limit; qopt.limit = q->limit;
qopt.loss = q->loss; qopt.loss = q->loss;
qopt.gap = q->gap; qopt.gap = q->gap;
qopt.duplicate = q->duplicate;
RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt); RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
cor.delay_corr = q->delay_cor.rho;
cor.loss_corr = q->loss_cor.rho;
cor.dup_corr = q->dup_cor.rho;
RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor);
rta->rta_len = skb->tail - b;
return skb->len; return skb->len;
rtattr_failure: rtattr_failure:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment