-
Notifications
You must be signed in to change notification settings - Fork 1
/
mcastjoiner.lua
120 lines (102 loc) · 2.9 KB
/
mcastjoiner.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#!/usr/bin/env lua
-- -*-lua-*-
--
-- $Id: mcastjoiner.lua $
--
-- Author: Markus Stenberg <markus [email protected]>
--
-- Copyright (c) 2013 cisco Systems, Inc.
--
-- Created: Thu Feb 21 11:53:52 2013 mstenber
-- Last modified: Mon May 27 09:48:22 2013 mstenber
-- Edit time: 14 min
--
-- Simple abstraction to handle multicast join/leave doing socket
-- Assume that subclasses or someone provides try_multicast_op - it is
-- our stubbable interface; alternatively, mcast6 (=group to join) and
-- mcasts (=socket to use) can be provided.
require 'mst'
module(..., package.seeall)
mcj = mst.create_class{class='mcj'}
function mcj:init()
-- joined if's
self.joined_if_set = mst.set:new{}
end
function mcj:uninit()
self:detach_skv()
end
function mcj:set_if_joined_set(shouldjoin)
self:d('set_if_joined_set', shouldjoin)
mst.sync_tables(self.joined_if_set, shouldjoin,
-- remove spurious
function (k, v)
self:leave_multicast(k)
end,
-- join new
function (k, v)
self:join_multicast(k)
end)
end
function mcj:join_multicast(ifname)
self:a(ifname, 'ifname mandatory')
local r, err = self:try_multicast_op(ifname, true)
if r
then
self.joined_if_set:insert(ifname)
else
mst.d('join_multicast failed', ifname, err)
end
end
function mcj:leave_multicast(ifname)
self:a(ifname, 'ifname mandatory')
local r, err = self:try_multicast_op(ifname, false)
if r
then
self.joined_if_set:remove(ifname)
else
mst.d('leave_multicast failed', ifname, err)
end
end
function mcj:try_multicast_op(ifname, is_join)
-- no real multicast socket -> no harm, no foul?
local s = self.mcasts
if not s then return end
local mcast6 = self.mcast6
self:a(self.mcast6)
local mct6 = {multiaddr=mcast6, interface=ifname}
local opname = (is_join and 'ipv6-add-membership') or 'ipv6-drop-membership'
mst.a(ifname and #ifname > 0)
mst.d('try_multicast_op', ifname, is_join)
return s:setoption(opname, mct6)
end
function mcj:attach_skv(skv, filter_lap)
-- detach if we already were attached
self:detach_skv()
-- and attach now
self.skv = skv
self.f = function (_, pl)
-- we can ignore key, we know it pl = list with
-- relevant bit the 'address' (while it's just one IP in
-- practise)
-- convert to normal IP's
local s = {}
for i, lap in ipairs(pl)
do
if (not filter_lap or filter_lap(lap)) and lap.ifname
then
s[lap.ifname] = true
end
end
self:set_if_joined_set(s)
end
self.skv:add_change_observer(self.f, elsa_pa.OSPF_LAP_KEY)
end
function mcj:detach_skv()
if not self.skv
then
return
end
self.skv:remove_change_observer(self.f, elsa_pa.OSPF_LAP_KEY)
self.skv = nil
self.f = nil
end