{"action":"created","comment":{"url":"https://api.github.com/repos/weaveworks/scope/pulls/comments/35741980","id":35741980,"diff_hunk":"@@ -0,0 +1,247 @@\n+package sniff\n+\n+import (\n+\t\"io\"\n+\t\"log\"\n+\t\"strconv\"\n+\t\"sync/atomic\"\n+\t\"time\"\n+\n+\t\"github.com/weaveworks/scope/report\"\n+\n+\t\"github.com/google/gopacket\"\n+\t\"github.com/google/gopacket/layers\"\n+)\n+\n+// Sniffer is a packet-sniffing reporter.\n+type Sniffer struct {\n+\thostID  string\n+\treports chan chan report.Report\n+\tparser  *gopacket.DecodingLayerParser\n+\tdecoded []gopacket.LayerType\n+\teth     layers.Ethernet\n+\tip4     layers.IPv4\n+\tip6     layers.IPv6\n+\ttcp     layers.TCP\n+\tudp     layers.UDP\n+\ticmp4   layers.ICMPv4\n+\ticmp6   layers.ICMPv6\n+}\n+\n+// New returns a new sniffing reporter that samples traffic by turning its\n+// packet capture facilities on and off. Note that the on and off durations\n+// represent a way to bound CPU burn. Effective sample rate needs to be\n+// calculated as (packets decoded / packets observed).\n+func New(hostID string, src gopacket.ZeroCopyPacketDataSource, on, off time.Duration) *Sniffer {\n+\ts := &Sniffer{\n+\t\thostID:  hostID,\n+\t\treports: make(chan chan report.Report),\n+\t}\n+\ts.parser = gopacket.NewDecodingLayerParser(\n+\t\tlayers.LayerTypeEthernet,\n+\t\t&s.eth, &s.ip4, &s.ip6, &s.tcp, &s.udp, &s.icmp4, &s.icmp6,\n+\t)\n+\tgo s.loop(src, on, off)\n+\treturn s\n+}\n+\n+// Report implements the Reporter interface.\n+func (s *Sniffer) Report() (report.Report, error) {\n+\tc := make(chan report.Report)\n+\ts.reports <- c\n+\treturn <-c, nil\n+}\n+\n+func (s *Sniffer) loop(src gopacket.ZeroCopyPacketDataSource, on, off time.Duration) {\n+\tvar (\n+\t\tprocess = uint64(1)               // initially enabled\n+\t\ttotal   = uint64(0)               // total packets seen\n+\t\tcount   = uint64(0)               // count of packets captured\n+\t\tpackets = make(chan Packet)       // decoded packets\n+\t\trpt     = report.MakeReport()     // the report we build\n+\t\tturnOn  = (<-chan time.Time)(nil) // signal to start capture (initially enabled)\n+\t\tturnOff = time.After(on)          // signal to stop capture\n+\t\tdone    = make(chan struct{})     // when src is finished, we're done too\n+\t)\n+\n+\tgo func() {\n+\t\ts.read(src, packets, &process, &total, &count)\n+\t\tclose(done)\n+\t}()\n+\n+\tfor {\n+\t\tselect {\n+\t\tcase p := <-packets:\n+\t\t\ts.Merge(p, rpt)","path":"probe/sniff/sniffer.go","position":75,"original_position":75,"commit_id":"177d831eb485214ea0f5ee68f8032d168c9ca0bc","original_commit_id":"177d831eb485214ea0f5ee68f8032d168c9ca0bc","user":{"login":"peterbourgon","id":114509,"avatar_url":"https://avatars.githubusercontent.com/u/114509?v=3","gravatar_id":"","url":"https://api.github.com/users/peterbourgon","html_url":"https://github.com/peterbourgon","followers_url":"https://api.github.com/users/peterbourgon/followers","following_url":"https://api.github.com/users/peterbourgon/following{/other_user}","gists_url":"https://api.github.com/users/peterbourgon/gists{/gist_id}","starred_url":"https://api.github.com/users/peterbourgon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/peterbourgon/subscriptions","organizations_url":"https://api.github.com/users/peterbourgon/orgs","repos_url":"https://api.github.com/users/peterbourgon/repos","events_url":"https://api.github.com/users/peterbourgon/events{/privacy}","received_events_url":"https://api.github.com/users/peterbourgon/received_events","type":"User","site_admin":false},"body":"In the on state, yes. Good catch. I think it'd be better to do a nonblocking send to the packets chan, what do you think?","created_at":"2015-07-29T09:31:48Z","updated_at":"2015-07-29T09:31:48Z","html_url":"https://github.com/weaveworks/scope/pull/317#discussion_r35741980","pull_request_url":"https://api.github.com/repos/weaveworks/scope/pulls/317","_links":{"self":{"href":"https://api.github.com/repos/weaveworks/scope/pulls/comments/35741980"},"html":{"href":"https://github.com/weaveworks/scope/pull/317#discussion_r35741980"},"pull_request":{"href":"https://api.github.com/repos/weaveworks/scope/pulls/317"}}},"pull_request":{"url":"https://api.github.com/repos/weaveworks/scope/pulls/317","id":39933873,"html_url":"https://github.com/weaveworks/scope/pull/317","diff_url":"https://github.com/weaveworks/scope/pull/317.diff","patch_url":"https://github.com/weaveworks/scope/pull/317.patch","issue_url":"https://api.github.com/repos/weaveworks/scope/issues/317","number":317,"state":"open","locked":false,"title":"gopacket sniffer","user":{"login":"peterbourgon","id":114509,"avatar_url":"https://avatars.githubusercontent.com/u/114509?v=3","gravatar_id":"","url":"https://api.github.com/users/peterbourgon","html_url":"https://github.com/peterbourgon","followers_url":"https://api.github.com/users/peterbourgon/followers","following_url":"https://api.github.com/users/peterbourgon/following{/other_user}","gists_url":"https://api.github.com/users/peterbourgon/gists{/gist_id}","starred_url":"https://api.github.com/users/peterbourgon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/peterbourgon/subscriptions","organizations_url":"https://api.github.com/users/peterbourgon/orgs","repos_url":"https://api.github.com/users/peterbourgon/repos","events_url":"https://api.github.com/users/peterbourgon/events{/privacy}","received_events_url":"https://api.github.com/users/peterbourgon/received_events","type":"User","site_admin":false},"body":"This PR adds packet sniffing to the probe's bag of tricks. Here's how it works:\r\n\r\n- We sample via a duty cycle, e.g. 1s on, 5s off.\r\n- When off, we still count (but don't decode) packets, this is necessary to compute a proper sample rate.\r\n- Currently gopacket/pcap only, could think about adding e.g. pfring.\r\n\r\nMisc notes from the implementation:\r\n\r\n- This removes the AggregateMetadata type, as (it turns out) we can merge EdgeMetadatas directly just fine.\r\n- There is no real concept of bytes ingress/egress on an edge, as an edge is directed. So those separate values have been removed. If there will be a concept of ingress/egress, it should be derived as part of the rendering process.\r\n- We can't cross-compile anymore :( so I had to remove the Darwin test from Circle.\r\n\r\nTo review, start with [the Sniffer](https://github.com/weaveworks/scope/pull/317/files#diff-12b45ef81ad4adaef7515ba523884796) and work your way out, being sure to look at how it's wired up [in probe.main](https://github.com/weaveworks/scope/pull/317/files#diff-3b8e458fa59e2dc53bde306a3e21b6e9). (It's modeled as a Reporter.)\r\n\r\nWe still need to wire this into the (revised) details pane, but I wanted to get this work reviewed and merged first.","created_at":"2015-07-14T16:20:18Z","updated_at":"2015-07-29T09:31:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f9fb4fcbcec1604e8638c2df6ab8ad62ed9f5537","assignee":{"login":"tomwilkie","id":444037,"avatar_url":"https://avatars.githubusercontent.com/u/444037?v=3","gravatar_id":"","url":"https://api.github.com/users/tomwilkie","html_url":"https://github.com/tomwilkie","followers_url":"https://api.github.com/users/tomwilkie/followers","following_url":"https://api.github.com/users/tomwilkie/following{/other_user}","gists_url":"https://api.github.com/users/tomwilkie/gists{/gist_id}","starred_url":"https://api.github.com/users/tomwilkie/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tomwilkie/subscriptions","organizations_url":"https://api.github.com/users/tomwilkie/orgs","repos_url":"https://api.github.com/users/tomwilkie/repos","events_url":"https://api.github.com/users/tomwilkie/events{/privacy}","received_events_url":"https://api.github.com/users/tomwilkie/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/weaveworks/scope/pulls/317/commits","review_comments_url":"https://api.github.com/repos/weaveworks/scope/pulls/317/comments","review_comment_url":"https://api.github.com/repos/weaveworks/scope/pulls/comments{/number}","comments_url":"https://api.github.com/repos/weaveworks/scope/issues/317/comments","statuses_url":"https://api.github.com/repos/weaveworks/scope/statuses/177d831eb485214ea0f5ee68f8032d168c9ca0bc","head":{"label":"weaveworks:sniff","ref":"sniff","sha":"177d831eb485214ea0f5ee68f8032d168c9ca0bc","user":{"login":"weaveworks","id":9976052,"avatar_url":"https://avatars.githubusercontent.com/u/9976052?v=3","gravatar_id":"","url":"https://api.github.com/users/weaveworks","html_url":"https://github.com/weaveworks","followers_url":"https://api.github.com/users/weaveworks/followers","following_url":"https://api.github.com/users/weaveworks/following{/other_user}","gists_url":"https://api.github.com/users/weaveworks/gists{/gist_id}","starred_url":"https://api.github.com/users/weaveworks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weaveworks/subscriptions","organizations_url":"https://api.github.com/users/weaveworks/orgs","repos_url":"https://api.github.com/users/weaveworks/repos","events_url":"https://api.github.com/users/weaveworks/events{/privacy}","received_events_url":"https://api.github.com/users/weaveworks/received_events","type":"Organization","site_admin":false},"repo":{"id":34659664,"name":"scope","full_name":"weaveworks/scope","owner":{"login":"weaveworks","id":9976052,"avatar_url":"https://avatars.githubusercontent.com/u/9976052?v=3","gravatar_id":"","url":"https://api.github.com/users/weaveworks","html_url":"https://github.com/weaveworks","followers_url":"https://api.github.com/users/weaveworks/followers","following_url":"https://api.github.com/users/weaveworks/following{/other_user}","gists_url":"https://api.github.com/users/weaveworks/gists{/gist_id}","starred_url":"https://api.github.com/users/weaveworks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weaveworks/subscriptions","organizations_url":"https://api.github.com/users/weaveworks/orgs","repos_url":"https://api.github.com/users/weaveworks/repos","events_url":"https://api.github.com/users/weaveworks/events{/privacy}","received_events_url":"https://api.github.com/users/weaveworks/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/weaveworks/scope","description":"Container visibility","fork":false,"url":"https://api.github.com/repos/weaveworks/scope","forks_url":"https://api.github.com/repos/weaveworks/scope/forks","keys_url":"https://api.github.com/repos/weaveworks/scope/keys{/key_id}","collaborators_url":"https://api.github.com/repos/weaveworks/scope/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/weaveworks/scope/teams","hooks_url":"https://api.github.com/repos/weaveworks/scope/hooks","issue_events_url":"https://api.github.com/repos/weaveworks/scope/issues/events{/number}","events_url":"https://api.github.com/repos/weaveworks/scope/events","assignees_url":"https://api.github.com/repos/weaveworks/scope/assignees{/user}","branches_url":"https://api.github.com/repos/weaveworks/scope/branches{/branch}","tags_url":"https://api.github.com/repos/weaveworks/scope/tags","blobs_url":"https://api.github.com/repos/weaveworks/scope/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/weaveworks/scope/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/weaveworks/scope/git/refs{/sha}","trees_url":"https://api.github.com/repos/weaveworks/scope/git/trees{/sha}","statuses_url":"https://api.github.com/repos/weaveworks/scope/statuses/{sha}","languages_url":"https://api.github.com/repos/weaveworks/scope/languages","stargazers_url":"https://api.github.com/repos/weaveworks/scope/stargazers","contributors_url":"https://api.github.com/repos/weaveworks/scope/contributors","subscribers_url":"https://api.github.com/repos/weaveworks/scope/subscribers","subscription_url":"https://api.github.com/repos/weaveworks/scope/subscription","commits_url":"https://api.github.com/repos/weaveworks/scope/commits{/sha}","git_commits_url":"https://api.github.com/repos/weaveworks/scope/git/commits{/sha}","comments_url":"https://api.github.com/repos/weaveworks/scope/comments{/number}","issue_comment_url":"https://api.github.com/repos/weaveworks/scope/issues/comments{/number}","contents_url":"https://api.github.com/repos/weaveworks/scope/contents/{+path}","compare_url":"https://api.github.com/repos/weaveworks/scope/compare/{base}...{head}","merges_url":"https://api.github.com/repos/weaveworks/scope/merges","archive_url":"https://api.github.com/repos/weaveworks/scope/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/weaveworks/scope/downloads","issues_url":"https://api.github.com/repos/weaveworks/scope/issues{/number}","pulls_url":"https://api.github.com/repos/weaveworks/scope/pulls{/number}","milestones_url":"https://api.github.com/repos/weaveworks/scope/milestones{/number}","notifications_url":"https://api.github.com/repos/weaveworks/scope/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/weaveworks/scope/labels{/name}","releases_url":"https://api.github.com/repos/weaveworks/scope/releases{/id}","created_at":"2015-04-27T10:12:35Z","updated_at":"2015-07-28T19:12:22Z","pushed_at":"2015-07-29T09:00:28Z","git_url":"git://github.com/weaveworks/scope.git","ssh_url":"git@github.com:weaveworks/scope.git","clone_url":"https://github.com/weaveworks/scope.git","svn_url":"https://github.com/weaveworks/scope","homepage":"http://weave.works/scope","size":25453,"stargazers_count":338,"watchers_count":338,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":14,"mirror_url":null,"open_issues_count":23,"forks":14,"open_issues":23,"watchers":338,"default_branch":"master"}},"base":{"label":"weaveworks:master","ref":"master","sha":"a565acc8712664f8caa5dfd54755daa185efb0fb","user":{"login":"weaveworks","id":9976052,"avatar_url":"https://avatars.githubusercontent.com/u/9976052?v=3","gravatar_id":"","url":"https://api.github.com/users/weaveworks","html_url":"https://github.com/weaveworks","followers_url":"https://api.github.com/users/weaveworks/followers","following_url":"https://api.github.com/users/weaveworks/following{/other_user}","gists_url":"https://api.github.com/users/weaveworks/gists{/gist_id}","starred_url":"https://api.github.com/users/weaveworks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weaveworks/subscriptions","organizations_url":"https://api.github.com/users/weaveworks/orgs","repos_url":"https://api.github.com/users/weaveworks/repos","events_url":"https://api.github.com/users/weaveworks/events{/privacy}","received_events_url":"https://api.github.com/users/weaveworks/received_events","type":"Organization","site_admin":false},"repo":{"id":34659664,"name":"scope","full_name":"weaveworks/scope","owner":{"login":"weaveworks","id":9976052,"avatar_url":"https://avatars.githubusercontent.com/u/9976052?v=3","gravatar_id":"","url":"https://api.github.com/users/weaveworks","html_url":"https://github.com/weaveworks","followers_url":"https://api.github.com/users/weaveworks/followers","following_url":"https://api.github.com/users/weaveworks/following{/other_user}","gists_url":"https://api.github.com/users/weaveworks/gists{/gist_id}","starred_url":"https://api.github.com/users/weaveworks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/weaveworks/subscriptions","organizations_url":"https://api.github.com/users/weaveworks/orgs","repos_url":"https://api.github.com/users/weaveworks/repos","events_url":"https://api.github.com/users/weaveworks/events{/privacy}","received_events_url":"https://api.github.com/users/weaveworks/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/weaveworks/scope","description":"Container visibility","fork":false,"url":"https://api.github.com/repos/weaveworks/scope","forks_url":"https://api.github.com/repos/weaveworks/scope/forks","keys_url":"https://api.github.com/repos/weaveworks/scope/keys{/key_id}","collaborators_url":"https://api.github.com/repos/weaveworks/scope/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/weaveworks/scope/teams","hooks_url":"https://api.github.com/repos/weaveworks/scope/hooks","issue_events_url":"https://api.github.com/repos/weaveworks/scope/issues/events{/number}","events_url":"https://api.github.com/repos/weaveworks/scope/events","assignees_url":"https://api.github.com/repos/weaveworks/scope/assignees{/user}","branches_url":"https://api.github.com/repos/weaveworks/scope/branches{/branch}","tags_url":"https://api.github.com/repos/weaveworks/scope/tags","blobs_url":"https://api.github.com/repos/weaveworks/scope/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/weaveworks/scope/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/weaveworks/scope/git/refs{/sha}","trees_url":"https://api.github.com/repos/weaveworks/scope/git/trees{/sha}","statuses_url":"https://api.github.com/repos/weaveworks/scope/statuses/{sha}","languages_url":"https://api.github.com/repos/weaveworks/scope/languages","stargazers_url":"https://api.github.com/repos/weaveworks/scope/stargazers","contributors_url":"https://api.github.com/repos/weaveworks/scope/contributors","subscribers_url":"https://api.github.com/repos/weaveworks/scope/subscribers","subscription_url":"https://api.github.com/repos/weaveworks/scope/subscription","commits_url":"https://api.github.com/repos/weaveworks/scope/commits{/sha}","git_commits_url":"https://api.github.com/repos/weaveworks/scope/git/commits{/sha}","comments_url":"https://api.github.com/repos/weaveworks/scope/comments{/number}","issue_comment_url":"https://api.github.com/repos/weaveworks/scope/issues/comments{/number}","contents_url":"https://api.github.com/repos/weaveworks/scope/contents/{+path}","compare_url":"https://api.github.com/repos/weaveworks/scope/compare/{base}...{head}","merges_url":"https://api.github.com/repos/weaveworks/scope/merges","archive_url":"https://api.github.com/repos/weaveworks/scope/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/weaveworks/scope/downloads","issues_url":"https://api.github.com/repos/weaveworks/scope/issues{/number}","pulls_url":"https://api.github.com/repos/weaveworks/scope/pulls{/number}","milestones_url":"https://api.github.com/repos/weaveworks/scope/milestones{/number}","notifications_url":"https://api.github.com/repos/weaveworks/scope/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/weaveworks/scope/labels{/name}","releases_url":"https://api.github.com/repos/weaveworks/scope/releases{/id}","created_at":"2015-04-27T10:12:35Z","updated_at":"2015-07-28T19:12:22Z","pushed_at":"2015-07-29T09:00:28Z","git_url":"git://github.com/weaveworks/scope.git","ssh_url":"git@github.com:weaveworks/scope.git","clone_url":"https://github.com/weaveworks/scope.git","svn_url":"https://github.com/weaveworks/scope","homepage":"http://weave.works/scope","size":25453,"stargazers_count":338,"watchers_count":338,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":14,"mirror_url":null,"open_issues_count":23,"forks":14,"open_issues":23,"watchers":338,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/weaveworks/scope/pulls/317"},"html":{"href":"https://github.com/weaveworks/scope/pull/317"},"issue":{"href":"https://api.github.com/repos/weaveworks/scope/issues/317"},"comments":{"href":"https://api.github.com/repos/weaveworks/scope/issues/317/comments"},"review_comments":{"href":"https://api.github.com/repos/weaveworks/scope/pulls/317/comments"},"review_comment":{"href":"https://api.github.com/repos/weaveworks/scope/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/weaveworks/scope/pulls/317/commits"},"statuses":{"href":"https://api.github.com/repos/weaveworks/scope/statuses/177d831eb485214ea0f5ee68f8032d168c9ca0bc"}}}}