On Mar 29, 2013, at 4:16 PM, Ben Pfaff wrote: > On Wed, Mar 27, 2013 at 11:02:21PM -0700, Neil Mckee wrote: >> This patch adds an sFlow test to the test suite (in branch 1.10). To make >> that work properly I added netdev_dummy_get_ifindex() so that a dummy netdev >> can return a dummy ifindex when asked. Is there anywhere in OVS that >> assumes that a netdev_dummy cannot make up a dummy ifindex? If so, I guess >> this behavior could be off by default and turned on just for this test. >> >> I have only tested this on a Fedora 17 OS. >> >> Signed-off-by: Neil McKee <neil.mc...@inmon.com> >> >> --- > > Thanks for the test! > > I noticed that the new test-sflow.c has the Apache 2 boilerplate > license text in it, which is fine, but the copyright notice should > probably mention InMon in place of or in addition to Nicira, since a > lot of the code in test-sflow.c is not written by Nicira. Neil, can > you give me a correct copyright notice for that file? >
How about we add the same copyright notice that appears at the top of all the lib/sflow* source files (just updating the year to 2013)? > Running this, I had some trouble with ifindexes. As written, the > ifindex that each dummy device receives depends on the order in which > they are created. That, in turn, depends on hash order in the > database and other factors. I decided to fix it by making the ifindex > a configurable property of the dummy devices, applying the following > incremental patch. Does that make sense? > Yes. Much better. I had started to do the same thing but baulked at the number of lines I was adding. > ---------------------------------------------------------------------- > diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c > index 04fd8b2..bdb3ea1 100644 > --- a/lib/netdev-dummy.c > +++ b/lib/netdev-dummy.c > @@ -98,7 +98,6 @@ netdev_dummy_create(const struct netdev_class *class, const > char *name, > struct netdev_dev **netdev_devp) > { > static unsigned int n = 0xaa550000; > - static unsigned int next_dummy_ifindex = 1001; > struct netdev_dev_dummy *netdev_dev; > > netdev_dev = xzalloc(sizeof *netdev_dev); > @@ -112,6 +111,7 @@ netdev_dummy_create(const struct netdev_class *class, > const char *name, > netdev_dev->mtu = 1500; > netdev_dev->flags = 0; > netdev_dev->change_seq = 1; > + netdev_dev->ifindex = -EOPNOTSUPP; > list_init(&netdev_dev->devs); > > shash_add(&dummy_netdev_devs, name, netdev_dev); > @@ -120,8 +120,6 @@ netdev_dummy_create(const struct netdev_class *class, > const char *name, > > *netdev_devp = &netdev_dev->netdev_dev; > > - netdev_dev->ifindex = next_dummy_ifindex++; > - > return 0; > } > > @@ -136,6 +134,27 @@ netdev_dummy_destroy(struct netdev_dev *netdev_dev_) > } > > static int > +netdev_dummy_get_config(struct netdev_dev *netdev_dev_, struct smap *args) > +{ > + struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_); > + > + if (netdev_dev->ifindex >= 0) { > + smap_add_format(args, "ifindex", "%d", netdev_dev->ifindex); > + } > + return 0; > +} > + > +static int > +netdev_dummy_set_config(struct netdev_dev *netdev_dev_, > + const struct smap *args) > +{ > + struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_); > + > + netdev_dev->ifindex = smap_get_int(args, "ifindex", -EOPNOTSUPP); > + return 0; > +} > + > +static int > netdev_dummy_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp) > { > struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_); > @@ -350,8 +369,8 @@ static const struct netdev_class dummy_class = { > > netdev_dummy_create, > netdev_dummy_destroy, > - NULL, /* get_config */ > - NULL, /* set_config */ > + netdev_dummy_get_config, > + netdev_dummy_set_config, > NULL, /* get_tunnel_config */ > > netdev_dummy_open, > @@ -369,7 +388,7 @@ static const struct netdev_class dummy_class = { > netdev_dummy_get_etheraddr, > netdev_dummy_get_mtu, > netdev_dummy_set_mtu, > - netdev_dummy_get_ifindex, /* get_ifindex */ > + netdev_dummy_get_ifindex, > NULL, /* get_carrier */ > NULL, /* get_carrier_resets */ > NULL, /* get_miimon */ > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index e9d52bb..7e12f2d 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -1213,6 +1213,9 @@ SFLOW_PORT=`cat stdout` > OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone]) > ADD_OF_PORTS([br0], 1, 2) > ovs-vsctl \ > + set Interface br0 options:ifindex=1002 -- \ > + set Interface p1 options:ifindex=1004 -- \ > + set Interface p2 options:ifindex=1003 -- \ > set Bridge br0 sflow=@sf -- \ > --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \ > header=128 sampling=1 polling=1 > ---------------------------------------------------------------------- > > At that point, I noticed that there was timing sensitivity. Applying > the following incremental fixed that: > > ---------------------------------------------------------------------- > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index 7e12f2d..3804b1a 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -1211,6 +1211,9 @@ AT_SETUP([ofproto-dpif - sFlow packet sampling]) > AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout]) > SFLOW_PORT=`cat stdout` > OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone]) > + > +ovs-appctl time/stop > + > ADD_OF_PORTS([br0], 1, 2) > ovs-vsctl \ > set Interface br0 options:ifindex=1002 -- \ > @@ -1239,7 +1242,9 @@ ovs-appctl netdev-dummy/receive p2 > 'in_port(1),eth(src=50:54:00:00:00:07,dst=50: > > dnl sleep long enough to get more than one counter sample > dnl from each datasource so we can check sequence numbers > -sleep 3 > +for i in `seq 1 30`; do > + ovs-appctl time/warp 100 > +done > OVS_VSWITCHD_STOP > ovs-appctl -t test-sflow exit > ---------------------------------------------------------------------- > > Even after I applied those changes, the test still didn't pass for me. > When I looked more closely, some of the expected output didn't > entirely make sense. For example, my reading of the sflow spec says > that samplePool should more or less count upward, which is what I > actually saw in the test output, but the expected output provided in > the patch shows all the samplePool values as 0. Some of the other > expected output needed to be adjusted too. > I wonder why your samplePool numbers are incrementing and mine are not? The samplePool is supplied in ofproto-dpif-sflow.c:dpif-sflow-received(): fs.sample_pool = stats.rx_packets; So I was assuming that since netdev-dummy doesn't seem to increment any of if's interface-counter stats then that would account for rx_packets being always 0. Does this vary depending on the presence or absence of the kernel module, or something like that? > While I was comparing the expected output, I realized that it was much > easier to read the diffs if each packet was described on multiple > lines, since diffs of very long lines with few differences are hard to > read. So I ended up applying the following incremental that both > makes the test pass for me and makes diff output easier to read: > OK. I was thinking that we should probably also change "grep HEADER" to something like "egrep 'HEADER|ERROR' to make certain than any exception flagged in the sflow-test.c code is certain to get through and break the test. Same thing for "grep IFCOUNTERS". I hesitated because I don't know how portable that egrep construct is. Just two minor questions left: 1) I wanted to craft a test packet with an odd-numbered length between 64 and 128 bytes, and another with > 128 bytes. Where should I look for documentation on that packet-construction language? Can I specify something like ipv6-over-vxlan-over-ipv4-over-mpls? I'm not concerned about this for now, just thinking about future enhancements to the test. 2) Are you really going to let me away with 2-character indentation in C? Regards, Neil > ---------------------------------------------------------------------- > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index 3804b1a..497b463 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -1248,21 +1248,250 @@ done > OVS_VSWITCHD_STOP > ovs-appctl -t test-sflow exit > > -AT_CHECK([[sort sflow.log | grep HEADER]], [0], > - [HEADER dgramSeqNo=1 ds=127.0.0.1>0:1003 fsSeqNo=1 in_vlan=0 in_priority=0 > out_vlan=0 out_priority=0 meanSkip=1 samplePool=0 dropEvents=0 > in_ifindex=1003 in_format=0 out_ifindex=2 out_format=2 hdr_prot=1 pkt_len=64 > stripped=4 hdr_len=60 > hdr=FF-FF-FF-FF-FF-FF-50-54-00-00-00-07-08-06-00-01-08-00-06-04-00-01-50-54-00-00-00-07-C0-A8-00-01-00-00-00-00-00-00-C0-A8-00-02-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > -HEADER dgramSeqNo=1 ds=127.0.0.1>0:1003 fsSeqNo=2 in_vlan=0 in_priority=0 > out_vlan=0 out_priority=0 meanSkip=1 samplePool=0 dropEvents=0 > in_ifindex=1003 in_format=0 out_ifindex=1004 out_format=0 hdr_prot=1 > pkt_len=64 stripped=4 hdr_len=60 > hdr=50-54-00-00-00-05-50-54-00-00-00-07-08-00-45-00-00-1C-00-00-00-00-40-01-F9-8D-C0-A8-00-02-C0-A8-00-01-00-00-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > -HEADER dgramSeqNo=1 ds=127.0.0.1>0:1003 fsSeqNo=3 in_vlan=0 in_priority=0 > out_vlan=0 out_priority=0 meanSkip=1 samplePool=0 dropEvents=0 > in_ifindex=1003 in_format=0 out_ifindex=1004 out_format=0 hdr_prot=1 > pkt_len=64 stripped=4 hdr_len=60 > hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > -HEADER dgramSeqNo=1 ds=127.0.0.1>0:1004 fsSeqNo=1 in_vlan=0 in_priority=0 > out_vlan=0 out_priority=0 meanSkip=1 samplePool=0 dropEvents=0 > in_ifindex=1004 in_format=0 out_ifindex=2 out_format=2 hdr_prot=1 pkt_len=64 > stripped=4 hdr_len=60 > hdr=FF-FF-FF-FF-FF-FF-50-54-00-00-00-05-08-06-00-01-08-00-06-04-00-01-50-54-00-00-00-05-C0-A8-00-02-00-00-00-00-00-00-C0-A8-00-01-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > -HEADER dgramSeqNo=1 ds=127.0.0.1>0:1004 fsSeqNo=2 in_vlan=0 in_priority=0 > out_vlan=0 out_priority=0 meanSkip=1 samplePool=0 dropEvents=0 > in_ifindex=1004 in_format=0 out_ifindex=1003 out_format=0 hdr_prot=1 > pkt_len=64 stripped=4 hdr_len=60 > hdr=50-54-00-00-00-07-50-54-00-00-00-05-08-00-45-00-00-1C-00-00-00-00-40-01-F9-8D-C0-A8-00-01-C0-A8-00-02-08-00-F7-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > -]) > - > -AT_CHECK([[sort sflow.log | grep IFCOUNTERS | head -6]], [0], > - [IFCOUNTERS dgramSeqNo=2 ds=127.0.0.1>0:1002 csSeqNo=1 ifindex=1002 type=6 > ifspeed=100000000 direction=0 status=3 in_octets=0 in_unicasts=0 > in_multicasts=0 in_broadcasts=4294967295 in_discards=0 in_errors=0 > in_unknownprotos=4294967295 out_octets=0 out_unicasts=0 > out_multicasts=4294967295 out_broadcasts=4294967295 out_discards=0 > out_errors=0 promiscuous=0 > -IFCOUNTERS dgramSeqNo=2 ds=127.0.0.1>0:1003 csSeqNo=1 ifindex=1003 type=6 > ifspeed=100000000 direction=0 status=0 in_octets=0 in_unicasts=0 > in_multicasts=0 in_broadcasts=4294967295 in_discards=0 in_errors=0 > in_unknownprotos=4294967295 out_octets=0 out_unicasts=0 > out_multicasts=4294967295 out_broadcasts=4294967295 out_discards=0 > out_errors=0 promiscuous=0 > -IFCOUNTERS dgramSeqNo=2 ds=127.0.0.1>0:1004 csSeqNo=1 ifindex=1004 type=6 > ifspeed=100000000 direction=0 status=0 in_octets=0 in_unicasts=0 > in_multicasts=0 in_broadcasts=4294967295 in_discards=0 in_errors=0 > in_unknownprotos=4294967295 out_octets=0 out_unicasts=0 > out_multicasts=4294967295 out_broadcasts=4294967295 out_discards=0 > out_errors=0 promiscuous=0 > -IFCOUNTERS dgramSeqNo=3 ds=127.0.0.1>0:1002 csSeqNo=2 ifindex=1002 type=6 > ifspeed=100000000 direction=0 status=3 in_octets=0 in_unicasts=0 > in_multicasts=0 in_broadcasts=4294967295 in_discards=0 in_errors=0 > in_unknownprotos=4294967295 out_octets=0 out_unicasts=0 > out_multicasts=4294967295 out_broadcasts=4294967295 out_discards=0 > out_errors=0 promiscuous=0 > -IFCOUNTERS dgramSeqNo=3 ds=127.0.0.1>0:1003 csSeqNo=2 ifindex=1003 type=6 > ifspeed=100000000 direction=0 status=0 in_octets=0 in_unicasts=0 > in_multicasts=0 in_broadcasts=4294967295 in_discards=0 in_errors=0 > in_unknownprotos=4294967295 out_octets=0 out_unicasts=0 > out_multicasts=4294967295 out_broadcasts=4294967295 out_discards=0 > out_errors=0 promiscuous=0 > -IFCOUNTERS dgramSeqNo=3 ds=127.0.0.1>0:1004 csSeqNo=2 ifindex=1004 type=6 > ifspeed=100000000 direction=0 status=0 in_octets=0 in_unicasts=0 > in_multicasts=0 in_broadcasts=4294967295 in_discards=0 in_errors=0 > in_unknownprotos=4294967295 out_octets=0 out_unicasts=0 > out_multicasts=4294967295 out_broadcasts=4294967295 out_discards=0 > out_errors=0 promiscuous=0 > +AT_CHECK([[sort sflow.log | grep HEADER | sed 's/ /\ > + /g']], [0], [dnl > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1003 > + fsSeqNo=1 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=1 > + dropEvents=0 > + in_ifindex=1003 > + in_format=0 > + out_ifindex=2 > + out_format=2 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=FF-FF-FF-FF-FF-FF-50-54-00-00-00-07-08-06-00-01-08-00-06-04-00-01-50-54-00-00-00-07-C0-A8-00-01-00-00-00-00-00-00-C0-A8-00-02-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1003 > + fsSeqNo=2 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=2 > + dropEvents=0 > + in_ifindex=1003 > + in_format=0 > + out_ifindex=1004 > + out_format=0 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=50-54-00-00-00-05-50-54-00-00-00-07-08-00-45-00-00-1C-00-00-00-00-40-01-F9-8D-C0-A8-00-02-C0-A8-00-01-00-00-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1003 > + fsSeqNo=3 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=3 > + dropEvents=0 > + in_ifindex=1003 > + in_format=0 > + out_ifindex=1004 > + out_format=0 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1004 > + fsSeqNo=1 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=1 > + dropEvents=0 > + in_ifindex=1004 > + in_format=0 > + out_ifindex=2 > + out_format=2 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=FF-FF-FF-FF-FF-FF-50-54-00-00-00-05-08-06-00-01-08-00-06-04-00-01-50-54-00-00-00-05-C0-A8-00-02-00-00-00-00-00-00-C0-A8-00-01-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1004 > + fsSeqNo=2 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=2 > + dropEvents=0 > + in_ifindex=1004 > + in_format=0 > + out_ifindex=1003 > + out_format=0 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=50-54-00-00-00-07-50-54-00-00-00-05-08-00-45-00-00-1C-00-00-00-00-40-01-F9-8D-C0-A8-00-01-C0-A8-00-02-08-00-F7-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +]) > + > +AT_CHECK([[sort sflow.log | grep IFCOUNTERS | head -6 | sed 's/ /\ > + /g']], [0], [dnl > +IFCOUNTERS > + dgramSeqNo=2 > + ds=127.0.0.1>0:1002 > + csSeqNo=1 > + ifindex=1002 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=3 > + in_octets=0 > + in_unicasts=0 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=120 > + out_unicasts=2 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=2 > + ds=127.0.0.1>0:1003 > + csSeqNo=1 > + ifindex=1003 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=0 > + in_octets=98 > + in_unicasts=3 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=120 > + out_unicasts=2 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=2 > + ds=127.0.0.1>0:1004 > + csSeqNo=1 > + ifindex=1004 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=0 > + in_octets=84 > + in_unicasts=2 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=180 > + out_unicasts=3 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=3 > + ds=127.0.0.1>0:1002 > + csSeqNo=2 > + ifindex=1002 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=3 > + in_octets=0 > + in_unicasts=0 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=120 > + out_unicasts=2 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=3 > + ds=127.0.0.1>0:1003 > + csSeqNo=2 > + ifindex=1003 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=0 > + in_octets=98 > + in_unicasts=3 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=120 > + out_unicasts=2 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=3 > + ds=127.0.0.1>0:1004 > + csSeqNo=2 > + ifindex=1004 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=0 > + in_octets=84 > + in_unicasts=2 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=180 > + out_unicasts=3 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > ]) > AT_CLEANUP > ---------------------------------------------------------------------- > > With that change, this test passes for me. > > Here's the full revised patch. > > --8<--------------------------cut here-------------------------->8-- > > From: Neil Mckee <neil.mc...@inmon.com> > Date: Wed, 27 Mar 2013 23:02:21 -0700 > Subject: [PATCH] test suite : add sFlow test > > This patch adds an sFlow test to the test suite (in branch 1.10). To make > that work properly I added netdev_dummy_get_ifindex() so that a dummy netdev > can return a dummy ifindex when asked. Is there anywhere in OVS that > assumes that a netdev_dummy cannot make up a dummy ifindex? If so, I guess > this behavior could be off by default and turned on just for this test. > > I have only tested this on a Fedora 17 OS. > > Signed-off-by: Neil McKee <neil.mc...@inmon.com> > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > lib/netdev-dummy.c | 38 ++++- > tests/automake.mk | 4 + > tests/ofproto-dpif.at | 291 ++++++++++++++++++++++++++ > tests/test-sflow.c | 539 +++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 869 insertions(+), 3 deletions(-) > create mode 100644 tests/test-sflow.c > > diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c > index 234d7bc..bdb3ea1 100644 > --- a/lib/netdev-dummy.c > +++ b/lib/netdev-dummy.c > @@ -51,6 +51,7 @@ struct netdev_dev_dummy { > unsigned int change_seq; > > struct list devs; /* List of child "netdev_dummy"s. */ > + int ifindex; > }; > > struct netdev_dummy { > @@ -110,6 +111,7 @@ netdev_dummy_create(const struct netdev_class *class, > const char *name, > netdev_dev->mtu = 1500; > netdev_dev->flags = 0; > netdev_dev->change_seq = 1; > + netdev_dev->ifindex = -EOPNOTSUPP; > list_init(&netdev_dev->devs); > > shash_add(&dummy_netdev_devs, name, netdev_dev); > @@ -132,6 +134,27 @@ netdev_dummy_destroy(struct netdev_dev *netdev_dev_) > } > > static int > +netdev_dummy_get_config(struct netdev_dev *netdev_dev_, struct smap *args) > +{ > + struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_); > + > + if (netdev_dev->ifindex >= 0) { > + smap_add_format(args, "ifindex", "%d", netdev_dev->ifindex); > + } > + return 0; > +} > + > +static int > +netdev_dummy_set_config(struct netdev_dev *netdev_dev_, > + const struct smap *args) > +{ > + struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_); > + > + netdev_dev->ifindex = smap_get_int(args, "ifindex", -EOPNOTSUPP); > + return 0; > +} > + > +static int > netdev_dummy_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp) > { > struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_); > @@ -284,6 +307,15 @@ netdev_dummy_set_stats(struct netdev *netdev, const > struct netdev_stats *stats) > } > > static int > +netdev_dummy_get_ifindex(const struct netdev *netdev) > +{ > + struct netdev_dev_dummy *dev = > + netdev_dev_dummy_cast(netdev_get_dev(netdev)); > + > + return dev->ifindex; > +} > + > +static int > netdev_dummy_update_flags(struct netdev *netdev, > enum netdev_flags off, enum netdev_flags on, > enum netdev_flags *old_flagsp) > @@ -337,8 +369,8 @@ static const struct netdev_class dummy_class = { > > netdev_dummy_create, > netdev_dummy_destroy, > - NULL, /* get_config */ > - NULL, /* set_config */ > + netdev_dummy_get_config, > + netdev_dummy_set_config, > NULL, /* get_tunnel_config */ > > netdev_dummy_open, > @@ -356,7 +388,7 @@ static const struct netdev_class dummy_class = { > netdev_dummy_get_etheraddr, > netdev_dummy_get_mtu, > netdev_dummy_set_mtu, > - NULL, /* get_ifindex */ > + netdev_dummy_get_ifindex, > NULL, /* get_carrier */ > NULL, /* get_carrier_resets */ > NULL, /* get_miimon */ > diff --git a/tests/automake.mk b/tests/automake.mk > index b11e0a2..275ff53 100644 > --- a/tests/automake.mk > +++ b/tests/automake.mk > @@ -232,6 +232,10 @@ noinst_PROGRAMS += tests/test-stp > tests_test_stp_SOURCES = tests/test-stp.c > tests_test_stp_LDADD = lib/libopenvswitch.a $(SSL_LIBS) > > +noinst_PROGRAMS += tests/test-sflow > +tests_test_sflow_SOURCES = tests/test-sflow.c > +tests_test_sflow_LDADD = lib/libopenvswitch.a $(SSL_LIBS) > + > noinst_PROGRAMS += tests/test-netflow > tests_test_netflow_SOURCES = tests/test-netflow.c > tests_test_netflow_LDADD = lib/libopenvswitch.a $(SSL_LIBS) > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index 96b166e..497b463 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -1206,6 +1206,297 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed > 's/[[0-9]]\{1,\}$/?/' | sort], > OVS_VSWITCHD_STOP > AT_CLEANUP > > +dnl Test that sFlow samples packets correctly. > +AT_SETUP([ofproto-dpif - sFlow packet sampling]) > +AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout]) > +SFLOW_PORT=`cat stdout` > +OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone]) > + > +ovs-appctl time/stop > + > +ADD_OF_PORTS([br0], 1, 2) > +ovs-vsctl \ > + set Interface br0 options:ifindex=1002 -- \ > + set Interface p1 options:ifindex=1004 -- \ > + set Interface p2 options:ifindex=1003 -- \ > + set Bridge br0 sflow=@sf -- \ > + --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \ > + header=128 sampling=1 polling=1 > +ON_EXIT([kill `cat test-sflow.pid`]) > +AT_CHECK([test-sflow --detach --no-chdir --pidfile $SFLOW_PORT:127.0.0.1 > > sflow.log]) > +AT_CAPTURE_FILE([sflow.log]) > + > +dnl open with ARP packets to seed the bridge-learning. The output > +dnl ifIndex numbers should be reported predictably after that. > +dnl Since we set sampling=1 we should see all of these packets > +dnl reported. Sorting the output by data-source and seqNo makes > +dnl it deterministic. Ensuring that we send at least two packets > +dnl into each port means we get to check the seq nos are > +dnl incrementing correctly. > + > +ovs-appctl netdev-dummy/receive p1 > 'in_port(2),eth(src=50:54:00:00:00:05,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.2,tip=192.168.0.1,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)' > +ovs-appctl netdev-dummy/receive p2 > 'in_port(1),eth(src=50:54:00:00:00:07,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:07,tha=00:00:00:00:00:00)' > +ovs-appctl netdev-dummy/receive p1 > 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)' > +ovs-appctl netdev-dummy/receive p2 > 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)' > +ovs-appctl netdev-dummy/receive p2 > 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x86dd),ipv6(src=fe80::1,dst=fe80::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)' > + > +dnl sleep long enough to get more than one counter sample > +dnl from each datasource so we can check sequence numbers > +for i in `seq 1 30`; do > + ovs-appctl time/warp 100 > +done > +OVS_VSWITCHD_STOP > +ovs-appctl -t test-sflow exit > + > +AT_CHECK([[sort sflow.log | grep HEADER | sed 's/ /\ > + /g']], [0], [dnl > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1003 > + fsSeqNo=1 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=1 > + dropEvents=0 > + in_ifindex=1003 > + in_format=0 > + out_ifindex=2 > + out_format=2 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=FF-FF-FF-FF-FF-FF-50-54-00-00-00-07-08-06-00-01-08-00-06-04-00-01-50-54-00-00-00-07-C0-A8-00-01-00-00-00-00-00-00-C0-A8-00-02-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1003 > + fsSeqNo=2 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=2 > + dropEvents=0 > + in_ifindex=1003 > + in_format=0 > + out_ifindex=1004 > + out_format=0 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=50-54-00-00-00-05-50-54-00-00-00-07-08-00-45-00-00-1C-00-00-00-00-40-01-F9-8D-C0-A8-00-02-C0-A8-00-01-00-00-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1003 > + fsSeqNo=3 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=3 > + dropEvents=0 > + in_ifindex=1003 > + in_format=0 > + out_ifindex=1004 > + out_format=0 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1004 > + fsSeqNo=1 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=1 > + dropEvents=0 > + in_ifindex=1004 > + in_format=0 > + out_ifindex=2 > + out_format=2 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=FF-FF-FF-FF-FF-FF-50-54-00-00-00-05-08-06-00-01-08-00-06-04-00-01-50-54-00-00-00-05-C0-A8-00-02-00-00-00-00-00-00-C0-A8-00-01-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +HEADER > + dgramSeqNo=1 > + ds=127.0.0.1>0:1004 > + fsSeqNo=2 > + in_vlan=0 > + in_priority=0 > + out_vlan=0 > + out_priority=0 > + meanSkip=1 > + samplePool=2 > + dropEvents=0 > + in_ifindex=1004 > + in_format=0 > + out_ifindex=1003 > + out_format=0 > + hdr_prot=1 > + pkt_len=64 > + stripped=4 > + hdr_len=60 > + > hdr=50-54-00-00-00-07-50-54-00-00-00-05-08-00-45-00-00-1C-00-00-00-00-40-01-F9-8D-C0-A8-00-01-C0-A8-00-02-08-00-F7-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 > +]) > + > +AT_CHECK([[sort sflow.log | grep IFCOUNTERS | head -6 | sed 's/ /\ > + /g']], [0], [dnl > +IFCOUNTERS > + dgramSeqNo=2 > + ds=127.0.0.1>0:1002 > + csSeqNo=1 > + ifindex=1002 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=3 > + in_octets=0 > + in_unicasts=0 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=120 > + out_unicasts=2 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=2 > + ds=127.0.0.1>0:1003 > + csSeqNo=1 > + ifindex=1003 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=0 > + in_octets=98 > + in_unicasts=3 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=120 > + out_unicasts=2 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=2 > + ds=127.0.0.1>0:1004 > + csSeqNo=1 > + ifindex=1004 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=0 > + in_octets=84 > + in_unicasts=2 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=180 > + out_unicasts=3 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=3 > + ds=127.0.0.1>0:1002 > + csSeqNo=2 > + ifindex=1002 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=3 > + in_octets=0 > + in_unicasts=0 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=120 > + out_unicasts=2 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=3 > + ds=127.0.0.1>0:1003 > + csSeqNo=2 > + ifindex=1003 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=0 > + in_octets=98 > + in_unicasts=3 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=120 > + out_unicasts=2 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +IFCOUNTERS > + dgramSeqNo=3 > + ds=127.0.0.1>0:1004 > + csSeqNo=2 > + ifindex=1004 > + type=6 > + ifspeed=100000000 > + direction=0 > + status=0 > + in_octets=84 > + in_unicasts=2 > + in_multicasts=0 > + in_broadcasts=4294967295 > + in_discards=0 > + in_errors=0 > + in_unknownprotos=4294967295 > + out_octets=180 > + out_unicasts=3 > + out_multicasts=4294967295 > + out_broadcasts=4294967295 > + out_discards=0 > + out_errors=0 > + promiscuous=0 > +]) > +AT_CLEANUP > + > + > + > dnl Test that basic NetFlow reports flow statistics correctly: > dnl - The initial packet of a flow are correctly accounted. > dnl - Later packets within a flow are correctly accounted. > diff --git a/tests/test-sflow.c b/tests/test-sflow.c > new file mode 100644 > index 0000000..ee3e6b3 > --- /dev/null > +++ b/tests/test-sflow.c > @@ -0,0 +1,539 @@ > +/* > + * Copyright (c) 2011, 2012 Nicira, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > + > +#include <errno.h> > +#include <getopt.h> > +#include <signal.h> > +#include <stdlib.h> > +#include <unistd.h> > +#include <setjmp.h> > + > +#include "command-line.h" > +#include "daemon.h" > +#include "dynamic-string.h" > +#include "netflow.h" > +#include "ofpbuf.h" > +#include "packets.h" > +#include "poll-loop.h" > +#include "socket-util.h" > +#include "unixctl.h" > +#include "util.h" > +#include "vlog.h" > + > +static void usage(void) NO_RETURN; > +static void parse_options(int argc, char *argv[]); > + > +static unixctl_cb_func test_sflow_exit; > + > +/* datagram */ > +#define SFLOW_VERSION_5 5 > +#define SFLOW_MIN_LEN 36 > +#define SFLOW_MAX_AGENTIP_STRLEN 64 > + > +/* sample tag numbers */ > +#define SFLOW_FLOW_SAMPLE 1 > +#define SFLOW_COUNTERS_SAMPLE 2 > +#define SFLOW_FLOW_SAMPLE_EXPANDED 3 > +#define SFLOW_COUNTERS_SAMPLE_EXPANDED 4 > +/* structure element tag numbers */ > +#define SFLOW_TAG_CTR_IFCOUNTERS 1 > +#define SFLOW_TAG_PKT_HEADER 1 > +#define SFLOW_TAG_PKT_SWITCH 1001 > + > +typedef struct _SFlowAddr { > + enum { SFLOW_ADDRTYPE_undefined=0, SFLOW_ADDRTYPE_IP4, SFLOW_ADDRTYPE_IP6 > } type; > + union { > + uint32_t ip4; > + uint32_t ip6[4]; > + } a; > +} SFlowAddr; > + > +typedef struct _SFlowXDR { > + /* exceptions */ > + jmp_buf env; > + int errline; > + /* cursor */ > + uint32_t *datap; > + uint32_t i; > + uint32_t quads; > + /* agent */ > + SFlowAddr agentAddr; > + char agentIPStr[SFLOW_MAX_AGENTIP_STRLEN]; > + uint32_t subAgentId; > + uint32_t uptime_mS; > + /* datasource */ > + uint32_t dsClass; > + uint32_t dsIndex; > + /* sequence numbers */ > + uint32_t dgramSeqNo; > + uint32_t fsSeqNo; > + uint32_t csSeqNo; > + /* structure offsets */ > + struct { > + uint32_t HEADER; > + uint32_t SWITCH; > + uint32_t IFCOUNTERS; > + } offset; > + /* flow sample fields */ > + uint32_t meanSkipCount; > + uint32_t samplePool; > + uint32_t dropEvents; > + uint32_t inputPortFormat; > + uint32_t inputPort; > + uint32_t outputPortFormat; > + uint32_t outputPort; > +} SFlowXDR; > + > +#define SFLOWXDR_try(x) ((x->errline = setjmp(x->env)) == 0) > +#define SFLOWXDR_throw(x) longjmp(x->env, __LINE__) > +#define SFLOWXDR_assert(x, t) if(!(t)) SFLOWXDR_throw(x) > + > +#define SFLOWXDR_init(x,buf,len) do { x->datap = (uint32_t *)buf; x->quads > = (len >> 2); } while(0) > +#define SFLOWXDR_next(x) ntohl(x->datap[x->i++]) > +#define SFLOWXDR_next_n(x) x->datap[x->i++] > +#define SFLOWXDR_more(x,q) ((q + x->i) <= x->quads) > +#define SFLOWXDR_skip(x,q) x->i += q > +#define SFLOWXDR_skip_b(x,b) x->i += ((b+3)>>2) > +#define SFLOWXDR_mark(x,q) x->i + q > +#define SFLOWXDR_markOK(x,m) (m == x->i) > +#define SFLOWXDR_mark_unique(x, pi) do { if(*pi) SFLOWXDR_throw(x); (*pi) = > x->i; } while(0) > +#define SFLOWXDR_off_b() (x->i << 2) > +#define SFLOWXDR_setc(x,j) x->i = j > +#define SFLOWXDR_str(x) (char *)(x->datap + x->i) > + > +static uint64_t > +SFLOWXDR_next_int64(SFlowXDR *x) > +{ > + uint64_t scratch; > + scratch = SFLOWXDR_next(x); > + scratch <<= 32; > + scratch += SFLOWXDR_next(x); > + return scratch; > +} > + > +#if 0 // not used > +static float > +SFLOWXDR_next_float(SFlowXDR *x) > +{ > + float scratch_fl; > + uint32_t scratch_32; > + scratch_32 = SFLOWXDR_next(x); > + memcpy(&scratch_fl, &scratch_32, 4); > + return scratch_fl; > +} > +#endif > + > +static void > +processCounterSample(SFlowXDR *x) { > + if(x->offset.IFCOUNTERS) { > + SFLOWXDR_setc(x, x->offset.IFCOUNTERS); > + printf("IFCOUNTERS"); > + printf(" dgramSeqNo=%"PRIu32, x->dgramSeqNo); > + printf(" ds=%s>%"PRIu32":%"PRIu32, x->agentIPStr, x->dsClass, > x->dsIndex); > + printf(" csSeqNo=%"PRIu32, x->csSeqNo); > + printf(" ifindex=%"PRIu32, SFLOWXDR_next(x)); > + printf(" type=%"PRIu32, SFLOWXDR_next(x)); > + printf(" ifspeed=%"PRIu64, SFLOWXDR_next_int64(x)); > + printf(" direction=%"PRIu32, SFLOWXDR_next(x)); > + printf(" status=%"PRIu32, SFLOWXDR_next(x)); > + printf(" in_octets=%"PRIu64, SFLOWXDR_next_int64(x)); > + printf(" in_unicasts=%"PRIu32, SFLOWXDR_next(x)); > + printf(" in_multicasts=%"PRIu32, SFLOWXDR_next(x)); > + printf(" in_broadcasts=%"PRIu32, SFLOWXDR_next(x)); > + printf(" in_discards=%"PRIu32, SFLOWXDR_next(x)); > + printf(" in_errors=%"PRIu32, SFLOWXDR_next(x)); > + printf(" in_unknownprotos=%"PRIu32, SFLOWXDR_next(x)); > + printf(" out_octets=%"PRIu64, SFLOWXDR_next_int64(x)); > + printf(" out_unicasts=%"PRIu32, SFLOWXDR_next(x)); > + printf(" out_multicasts=%"PRIu32, SFLOWXDR_next(x)); > + printf(" out_broadcasts=%"PRIu32, SFLOWXDR_next(x)); > + printf(" out_discards=%"PRIu32, SFLOWXDR_next(x)); > + printf(" out_errors=%"PRIu32, SFLOWXDR_next(x)); > + printf(" promiscuous=%"PRIu32, SFLOWXDR_next(x)); > + printf("\n"); > + } > +} > + > +#define bin2hex(nib) (((nib) < 10) ? ('0' + (nib)) : ('A' - 10 + (nib))) > + > +static int printHex(const char *a, int len, char *buf, int bufLen) > +{ > + int b = 0, i = 0; > + unsigned char nextByte; > + for (; i < len; i++) { > + if(b > (bufLen - 10)) break; > + nextByte = a[i]; > + buf[b++] = bin2hex(nextByte >> 4); > + buf[b++] = bin2hex(nextByte & 0x0f); > + if(i < (len - 1)) buf[b++] = '-'; > + } > + buf[b] = '\0'; > + return b; > +} > + > +#define SFLOW_HEX_SCRATCH 1024 > + > +static void > +processFlowSample(SFlowXDR *x) { > + if(x->offset.HEADER) { > + uint32_t headerLen; > + char scratch[SFLOW_HEX_SCRATCH]; > + > + printf("HEADER"); > + printf(" dgramSeqNo=%"PRIu32, x->dgramSeqNo); > + printf(" ds=%s>%"PRIu32":%"PRIu32, x->agentIPStr, x->dsClass, > x->dsIndex); > + printf(" fsSeqNo=%"PRIu32, x->fsSeqNo); > + > + if(x->offset.SWITCH) { > + SFLOWXDR_setc(x, x->offset.SWITCH); > + printf(" in_vlan=%"PRIu32, SFLOWXDR_next(x)); > + printf(" in_priority=%"PRIu32, SFLOWXDR_next(x)); > + printf(" out_vlan=%"PRIu32, SFLOWXDR_next(x)); > + printf(" out_priority=%"PRIu32, SFLOWXDR_next(x)); > + } > + > + SFLOWXDR_setc(x, x->offset.HEADER); > + printf(" meanSkip=%"PRIu32, x->meanSkipCount); > + printf(" samplePool=%"PRIu32, x->samplePool); > + printf(" dropEvents=%"PRIu32, x->dropEvents); > + printf(" in_ifindex=%"PRIu32, x->inputPort); > + printf(" in_format=%"PRIu32, x->inputPortFormat); > + printf(" out_ifindex=%"PRIu32, x->outputPort); > + printf(" out_format=%"PRIu32, x->outputPortFormat); > + printf(" hdr_prot=%"PRIu32, SFLOWXDR_next(x)); > + printf(" pkt_len=%"PRIu32, SFLOWXDR_next(x)); > + printf(" stripped=%"PRIu32, SFLOWXDR_next(x)); > + headerLen = SFLOWXDR_next(x); > + printf(" hdr_len=%"PRIu32, headerLen); > + printHex(SFLOWXDR_str(x), headerLen, scratch, SFLOW_HEX_SCRATCH); > + printf(" hdr=%s", scratch); > + printf("\n"); > + } > +} > + > +static void > +processDatagram(SFlowXDR *x) > +{ > + uint32_t samples,s; > + > + SFLOWXDR_assert(x, (SFLOWXDR_next(x) == SFLOW_VERSION_5)); > + /* read the sFlow header */ > + x->agentAddr.type = SFLOWXDR_next(x); > + switch(x->agentAddr.type) { > + case SFLOW_ADDRTYPE_IP4: > + x->agentAddr.a.ip4 = SFLOWXDR_next_n(x); > + break; > + case SFLOW_ADDRTYPE_IP6: > + x->agentAddr.a.ip6[0] = SFLOWXDR_next_n(x); > + x->agentAddr.a.ip6[1] = SFLOWXDR_next_n(x); > + x->agentAddr.a.ip6[2] = SFLOWXDR_next_n(x); > + x->agentAddr.a.ip6[3] = SFLOWXDR_next_n(x); > + break; > + case SFLOW_ADDRTYPE_undefined: > + default: > + SFLOWXDR_throw(x); > + break; > + } > + x->subAgentId = SFLOWXDR_next(x); > + x->dgramSeqNo = SFLOWXDR_next(x); > + x->uptime_mS = SFLOWXDR_next(x); > + > + /* store the agent address as a string */ > + if(x->agentAddr.type == SFLOW_ADDRTYPE_IP6) { > + snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN, "%04x:%04x:%04x:%04x", > + x->agentAddr.a.ip6[0], > + x->agentAddr.a.ip6[1], > + x->agentAddr.a.ip6[2], > + x->agentAddr.a.ip6[3]); > + } > + else { > + snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN, IP_FMT, > IP_ARGS(x->agentAddr.a.ip4)); > + } > + > + /* array of flow/counter samples */ > + samples = SFLOWXDR_next(x); > + for(s = 0; s < samples; s++) { > + uint32_t sType = SFLOWXDR_next(x); > + uint32_t sQuads = SFLOWXDR_next(x) >> 2; > + uint32_t sMark = SFLOWXDR_mark(x,sQuads); > + SFLOWXDR_assert(x, SFLOWXDR_more(x,sQuads)); > + > + switch(sType) { > + case SFLOW_COUNTERS_SAMPLE_EXPANDED: > + case SFLOW_COUNTERS_SAMPLE: > + { > + uint32_t csElements, e; > + uint32_t ceTag, ceQuads, ceMark, csEnd; > + x->csSeqNo = SFLOWXDR_next(x); > + if(sType == SFLOW_COUNTERS_SAMPLE_EXPANDED) { > + x->dsClass = SFLOWXDR_next(x); > + x->dsIndex = SFLOWXDR_next(x); > + } > + else { > + uint32_t dsCombined = SFLOWXDR_next(x); > + x->dsClass = dsCombined >> 24; > + x->dsIndex = dsCombined & 0x00FFFFFF; > + } > + > + csElements = SFLOWXDR_next(x); > + for(e = 0; e < csElements; e++) { > + SFLOWXDR_assert(x, SFLOWXDR_more(x,2)); > + ceTag = SFLOWXDR_next(x); > + ceQuads = SFLOWXDR_next(x) >> 2; > + ceMark = SFLOWXDR_mark(x,ceQuads); > + SFLOWXDR_assert(x, SFLOWXDR_more(x,ceQuads)); > + /* only care about selected structures. > + * Just record their offsets here. We'll read the fields out later. */ > + switch(ceTag) { > + case SFLOW_TAG_CTR_IFCOUNTERS: SFLOWXDR_mark_unique(x, > &(x->offset.IFCOUNTERS)); break; > + /* add others here... */ > + } > + > + SFLOWXDR_skip(x,ceQuads); > + SFLOWXDR_assert(x, SFLOWXDR_markOK(x,ceMark)); > + } > + > + csEnd = SFLOWXDR_mark(x,0); > + processCounterSample(x); > + /* make sure we pick up the decoding where we left off */ > + SFLOWXDR_setc(x, csEnd); > + > + /* clear the offsets for the next sample */ > + memset(&x->offset, 0, sizeof(x->offset)); > + } > + break; > + > + case SFLOW_FLOW_SAMPLE: > + case SFLOW_FLOW_SAMPLE_EXPANDED: > + { > + uint32_t fsElements, e; > + uint32_t feTag, feQuads, feMark, fsEnd; > + x->fsSeqNo = SFLOWXDR_next(x); > + if(sType == SFLOW_FLOW_SAMPLE_EXPANDED) { > + x->dsClass = SFLOWXDR_next(x); > + x->dsIndex = SFLOWXDR_next(x); > + } > + else { > + uint32_t dsCombined = SFLOWXDR_next(x); > + x->dsClass = dsCombined >> 24; > + x->dsIndex = dsCombined & 0x00FFFFFF; > + } > + x->meanSkipCount = SFLOWXDR_next(x); > + x->samplePool = SFLOWXDR_next(x); > + x->dropEvents = SFLOWXDR_next(x); > + if(sType == SFLOW_FLOW_SAMPLE_EXPANDED) { > + x->inputPortFormat = SFLOWXDR_next(x); > + x->inputPort = SFLOWXDR_next(x); > + x->outputPortFormat = SFLOWXDR_next(x); > + x->outputPort = SFLOWXDR_next(x); > + } > + else { > + uint32_t inp, outp; > + inp = SFLOWXDR_next(x); > + outp = SFLOWXDR_next(x); > + x->inputPortFormat = inp >> 30; > + x->inputPort = inp & 0x3fffffff; > + x->outputPortFormat = outp >> 30; > + x->outputPort = outp & 0x3fffffff; > + } > + fsElements = SFLOWXDR_next(x); > + for(e = 0; e < fsElements; e++) { > + SFLOWXDR_assert(x, SFLOWXDR_more(x,2)); > + feTag = SFLOWXDR_next(x); > + feQuads = SFLOWXDR_next(x) >> 2; > + feMark = SFLOWXDR_mark(x,feQuads); > + SFLOWXDR_assert(x, SFLOWXDR_more(x,feQuads)); > + /* only care about selected structures. > + * Just record their offsets here. We'll read the fields out below. */ > + switch(feTag) { > + case SFLOW_TAG_PKT_HEADER: SFLOWXDR_mark_unique(x, > &x->offset.HEADER); break; > + case SFLOW_TAG_PKT_SWITCH: SFLOWXDR_mark_unique(x, > &x->offset.SWITCH); break; > + /* add others here... */ > + } > + > + SFLOWXDR_skip(x,feQuads); > + SFLOWXDR_assert(x, SFLOWXDR_markOK(x,feMark)); > + } > + > + > + fsEnd = SFLOWXDR_mark(x,0); > + processFlowSample(x); > + /* make sure we pick up the decoding where we left off */ > + SFLOWXDR_setc(x, fsEnd); > + > + /* clear the offsets for the next counter/flow sample */ > + memset(&x->offset, 0, sizeof(x->offset)); > + } > + break; > + default: > + /* skip other sample types */ > + SFLOWXDR_skip(x,sQuads); > + } > + SFLOWXDR_assert(x, SFLOWXDR_markOK(x,sMark)); > + } > +} > + > +static void > +print_sflow(struct ofpbuf *buf) > +{ > + char *dgram_buf; > + int dgram_len = buf->size; > + SFlowXDR xdrDatagram; > + SFlowXDR *x = &xdrDatagram; > + memset(x, 0, sizeof(SFlowXDR)); > + if(SFLOWXDR_try(x)) { > + SFLOWXDR_assert(x, (dgram_buf = ofpbuf_try_pull(buf, buf->size))); > + SFLOWXDR_init(x, dgram_buf, dgram_len); > + SFLOWXDR_assert(x, dgram_len >= SFLOW_MIN_LEN); > + processDatagram(x); > + } > + else { > + // CATCH > + printf("\n>>>>> ERROR in " __FILE__ " at line %u\n", x->errline); > + } > +} > + > +int > +main(int argc, char *argv[]) > +{ > + struct unixctl_server *server; > + enum { MAX_RECV = 1500 }; > + const char *target; > + struct ofpbuf buf; > + bool exiting = false; > + int error; > + int sock; > + > + proctitle_init(argc, argv); > + set_program_name(argv[0]); > + parse_options(argc, argv); > + > + if (argc - optind != 1) { > + ovs_fatal(0, "exactly one non-option argument required " > + "(use --help for help)"); > + } > + target = argv[optind]; > + > + sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0); > + if (sock < 0) { > + ovs_fatal(0, "%s: failed to open (%s)", argv[1], strerror(-sock)); > + } > + > + daemon_save_fd(STDOUT_FILENO); > + daemonize_start(); > + > + error = unixctl_server_create(NULL, &server); > + if (error) { > + ovs_fatal(error, "failed to create unixctl server"); > + } > + unixctl_command_register("exit", "", 0, 0, test_sflow_exit, &exiting); > + > + daemonize_complete(); > + > + ofpbuf_init(&buf, MAX_RECV); > + for (;;) { > + int retval; > + > + unixctl_server_run(server); > + > + ofpbuf_clear(&buf); > + do { > + retval = read(sock, buf.data, buf.allocated); > + } while (retval < 0 && errno == EINTR); > + if (retval > 0) { > + ofpbuf_put_uninit(&buf, retval); > + print_sflow(&buf); > + fflush(stdout); > + } > + > + if (exiting) { > + break; > + } > + > + poll_fd_wait(sock, POLLIN); > + unixctl_server_wait(server); > + poll_block(); > + } > + > + return 0; > +} > + > +static void > +parse_options(int argc, char *argv[]) > +{ > + enum { > + DAEMON_OPTION_ENUMS > + }; > + static struct option long_options[] = { > + {"verbose", optional_argument, NULL, 'v'}, > + {"help", no_argument, NULL, 'h'}, > + DAEMON_LONG_OPTIONS, > + {NULL, 0, NULL, 0}, > + }; > + char *short_options = long_options_to_short_options(long_options); > + > + for (;;) { > + int c = getopt_long(argc, argv, short_options, long_options, NULL); > + if (c == -1) { > + break; > + } > + > + switch (c) { > + case 'h': > + usage(); > + > + case 'v': > + vlog_set_verbosity(optarg); > + break; > + > + DAEMON_OPTION_HANDLERS > + > + case '?': > + exit(EXIT_FAILURE); > + > + default: > + abort(); > + } > + } > + free(short_options); > +} > + > +static void > +usage(void) > +{ > + printf("%s: sflow collector test utility\n" > + "usage: %s [OPTIONS] PORT[:IP]\n" > + "where PORT is the UDP port to listen on and IP is optionally\n" > + "the IP address to listen on.\n", > + program_name, program_name); > + daemon_usage(); > + vlog_usage(); > + printf("\nOther options:\n" > + " -h, --help display this help message\n"); > + exit(EXIT_SUCCESS); > +} > + > +static void > +test_sflow_exit(struct unixctl_conn *conn, > + int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, > + void *exiting_) > +{ > + bool *exiting = exiting_; > + *exiting = true; > + unixctl_command_reply(conn, NULL); > +} > -- > 1.7.2.5 > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev