blob: 70fd5c9df97ee38e9843b7dd08e28fe49382ea94 [file] [log] [blame]
Harald Welteb8bfc4e2011-10-11 18:49:59 +02001% Internal SS7 route database keeping
2
3% (C) 2011 by Harald Welte <laforge@gnumonks.org>
4%
5% All Rights Reserved
6%
7% This program is free software; you can redistribute it and/or modify
8% it under the terms of the GNU Affero General Public License as
9% published by the Free Software Foundation; either version 3 of the
10% License, or (at your option) any later version.
11%
12% This program is distributed in the hope that it will be useful,
13% but WITHOUT ANY WARRANTY; without even the implied warranty of
14% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15% GNU General Public License for more details.
16%
17% You should have received a copy of the GNU Affero General Public License
18% along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20-module(ss7_routes).
21-behaviour(gen_server).
22
23-include_lib("osmo_ss7/include/mtp3.hrl").
24
25% gen_fsm callbacks
26-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]).
27
28% our published API
29-export([start_link/0]).
30
31% client functions, may internally talk to our sccp_user server
32-export([create_route/3, delete_route/3]).
33-export([dump/0]).
34-export([route_dpc/1]).
35
36-record(ss7route, {
37 remote_pc_mask, % {remote_pc, remote_pc_mask}
38 linkset_name
39}).
40
41-record(sr_state, {
42 route_tbl
43}).
44
45% initialization code
46
47start_link() ->
48 gen_server:start_link({local, ?MODULE}, ?MODULE, [], [{debug, [trace]}]).
49
50init(_Arg) ->
51 RouteTbl = ets:new(ss7_routes, [ordered_set, named_table,
52 {keypos, #ss7route.remote_pc_mask}]),
53 process_flag(trap_exit, true),
54 {ok, #sr_state{route_tbl = RouteTbl}}.
55
56% client side API
57
58% all write operations go through gen_server:call(), as only the ?MODULE
59% process has permission to modify the table content
60
61create_route(RemotePc, RemoteMask, LinksetName) ->
62 gen_server:call(?MODULE, {create_route, {RemotePc, RemoteMask, LinksetName}}).
63
64delete_route(RemotePc, RemoteMask, LinksetName) ->
65 gen_server:call(?MODULE, {delete_route, {RemotePc, RemoteMask, LinksetName}}).
66
67% the lookup functions can directly use the ets named_table from within
68% the client process, no need to go through a synchronous IPC
69
70route_dpc(Dpc) ->
71 % this was generated by ets:fun2ms() on the shell
72 Match = [{#ss7route{remote_pc_mask={'$1','$2'},linkset_name='$3'},
73 [{'==',{'band',Dpc,'$2'},'$1'}],
74 ['$3']}],
75 case ets:select(ss7_routes, Match) of
76 [Name|_] ->
77 {ok, Name};
78 _ ->
79 {error, no_route}
80 end.
81
82dump() ->
83 List = ets:tab2list(ss7_routes),
84 dump_routes(List).
85
86dump_routes([]) ->
87 ok;
88dump_routes([Head|Tail]) when is_record(Head, ss7route) ->
89 dump_single_route(Head),
90 dump_routes(Tail).
91
92dump_single_route(#ss7route{remote_pc_mask = {Pc, Mask},
93 linkset_name = Name}) ->
94 io:format("Dest PC ~p/~p -> Linkset ~p~n",
95 [Pc, Mask, Name]).
96
97% server side code
98
99handle_call({create_route, {RemotePc, RemoteMask, Name}},
100 {_FromPid, _FromRef}, S) ->
101 #sr_state{route_tbl = Tbl} = S,
102 R = #ss7route{remote_pc_mask = {RemotePc, RemoteMask},
103 linkset_name = Name},
104 case ets:insert_new(Tbl, R) of
105 false ->
106 {reply, {error, ets_insert}, S};
107 _ ->
108 {reply, ok, S}
109 end;
110
111handle_call({delete_route, {RemotePc, RemoteMask, _Name}},
112 {_FromPid, _FromRef}, S) ->
113 #sr_state{route_tbl = Tbl} = S,
114 ets:delete(Tbl, {RemotePc, RemoteMask}),
115 {reply, ok, S}.
116
117handle_info(Info, S) ->
118 error_logger:error_report(["unknown handle_info",
119 {module, ?MODULE},
120 {info, Info}, {state, S}]),
121 {noreply, S}.
122
123terminate(Reason, _S) ->
124 io:format("terminating ~p with reason ~p", [?MODULE, Reason]),
125 ok.
126
127code_change(_OldVsn, State, _Extra) ->
128 {ok, State}.