From bba7f73220981a691e30b265819b5dcb88a491b5 Mon Sep 17 00:00:00 2001 From: Michael Jeffrey Date: Tue, 13 Jun 2023 10:38:58 -0700 Subject: [PATCH] add max_copies to skf filter (#969) --- rebar.lock | 2 +- src/apis/router_console_ws_worker.erl | 7 ++- src/device/router_device_worker.erl | 65 +++++++++++--------------- src/grpc/router_ics_skf_worker.erl | 36 ++++++++++---- test/router_ics_skf_worker_SUITE.erl | 11 +++-- test/router_test_ics_route_service.erl | 6 ++- 6 files changed, 71 insertions(+), 56 deletions(-) diff --git a/rebar.lock b/rebar.lock index 0299a684e..ee8335a1d 100644 --- a/rebar.lock +++ b/rebar.lock @@ -90,7 +90,7 @@ {<<"hackney">>,{pkg,<<"hackney">>,<<"1.18.1">>},0}, {<<"helium_proto">>, {git,"https://github.com/helium/proto.git", - {ref,"3061e06dff4f4a643dd9e2bf98bc24b462071de3"}}, + {ref,"91cd0c3953e8e233a86e6c67120a6df9b9b1cb40"}}, 0}, {<<"hpack">>, {git,"https://github.com/novalabsxyz/hpack.git", diff --git a/src/apis/router_console_ws_worker.erl b/src/apis/router_console_ws_worker.erl index 2b6ad0370..0d6d615f7 100644 --- a/src/apis/router_console_ws_worker.erl +++ b/src/apis/router_console_ws_worker.erl @@ -404,13 +404,16 @@ update_device_record(DB, CF, DeviceID) -> DevAddr ), NwkSKey = router_device:nwk_s_key(Device), + MultiBuy = maps:get(multi_buy, router_device:metadata(Device), 0), case IsActive of true -> - ok = router_ics_skf_worker:update([{add, DevAddrInt, NwkSKey}]), + ok = router_ics_skf_worker:update([{add, DevAddrInt, NwkSKey, MultiBuy}]), catch router_ics_eui_worker:add([DeviceID]), lager:debug("device un-paused, sent SKF and EUI add", []); false -> - ok = router_ics_skf_worker:update([{remove, DevAddrInt, NwkSKey}]), + ok = router_ics_skf_worker:update([ + {remove, DevAddrInt, NwkSKey, MultiBuy} + ]), catch router_ics_eui_worker:remove([DeviceID]), lager:debug("device paused, sent SKF and EUI remove", []) end diff --git a/src/device/router_device_worker.erl b/src/device/router_device_worker.erl index 5fe4faaf4..9d89430f1 100644 --- a/src/device/router_device_worker.erl +++ b/src/device/router_device_worker.erl @@ -422,11 +422,15 @@ handle_cast( NwkSKey = router_device:nwk_s_key(Device1), case IsActive of true -> - ok = router_ics_skf_worker:update([{add, DevAddrInt, NwkSKey}]), + ok = router_ics_skf_worker:update([ + {add, DevAddrInt, NwkSKey, MultiBuyValue} + ]), catch router_ics_eui_worker:add([DeviceID]), lager:debug("device un-paused, sent SKF and EUI add", []); false -> - ok = router_ics_skf_worker:update([{remove, DevAddrInt, NwkSKey}]), + ok = router_ics_skf_worker:update([ + {remove, DevAddrInt, NwkSKey, MultiBuyValue} + ]), catch router_ics_eui_worker:remove([DeviceID]), lager:debug("device paused, sent SKF and EUI remove", []) end @@ -760,7 +764,8 @@ handle_cast( false -> ok; true -> - ToAdd = [{add, DevAddr0, UsedNwkSKey}], + MultiBuy = maps:get(multi_buy, router_device:metadata(D1), 0), + ToAdd = [{add, DevAddr0, UsedNwkSKey, MultiBuy}], DevAddrToInt = fun(D) -> <> = lorawan_utils:reverse(D), @@ -769,12 +774,12 @@ handle_cast( %% We have to usort just in case DevAddr assigned is the same ToRemove0 = lists:usort([ - {remove, DevAddrToInt(DevAddr), NwkSKey} + {remove, DevAddrToInt(DevAddr), NwkSKey, MultiBuy} || {NwkSKey, _} <- Keys, DevAddr <- router_device:devaddrs(Device0) ]), %% Making sure that the pair that was added is not getting removed (just in case DevAddr assigned is the same) - ToRemove1 = ToRemove0 -- [{remove, DevAddr0, UsedNwkSKey}], + ToRemove1 = ToRemove0 -- [{remove, DevAddr0, UsedNwkSKey, MultiBuy}], ok = router_ics_skf_worker:update(ToAdd ++ ToRemove1), lager:debug("sending update skf ~p", [ToAdd ++ ToRemove1]) end, @@ -1363,8 +1368,9 @@ handle_join( {region, Region} ], Device1 = router_device:update(DeviceUpdates, Device0), + MultiBuy = maps:get(multi_buy, router_device:metadata(Device1), 0), - ok = handle_join_skf(NewKeys, NewDevaddrs), + ok = handle_join_skf(NewKeys, NewDevaddrs, MultiBuy), lager:debug( "Join DevEUI ~s with AppEUI ~s tried to join with nonce ~p region ~p via ~s", @@ -1388,9 +1394,10 @@ handle_join( %% attempts, we won't have the information to remove all the unused keys. -spec handle_join_skf( NewKeys :: list({NwkSKey :: binary(), AppSKey :: binary()}), - NewDevAddrs :: list(DevAddr :: binary()) + NewDevAddrs :: list(DevAddr :: binary()), + MaxCopies :: non_neg_integer() ) -> ok. -handle_join_skf([{NwkSKey, _} | _] = NewKeys, [NewDevAddr | _] = NewDevAddrs) -> +handle_join_skf([{NwkSKey, _} | _] = NewKeys, [NewDevAddr | _] = NewDevAddrs, MaxCopies) -> DevAddrToInt = fun(D) -> <> = lorawan_utils:reverse(D), Int @@ -1398,15 +1405,21 @@ handle_join_skf([{NwkSKey, _} | _] = NewKeys, [NewDevAddr | _] = NewDevAddrs) -> %% remove evicted keys from the config service for every devaddr. EvictedKeys = router_device:credentials_to_evict(NewKeys), - ToRemoveKeys = [{remove, DevAddrToInt(D), NSK} || {NSK, _} <- EvictedKeys, D <- NewDevAddrs], + ToRemoveKeys = [ + {remove, DevAddrToInt(D), NSK, MaxCopies} + || {NSK, _} <- EvictedKeys, D <- NewDevAddrs + ], %% remove evicted devaddrs from the config service for every nwkskey. EvictedAddrs = router_device:credentials_to_evict(NewDevAddrs), - ToRemoveAddrs = [{remove, DevAddrToInt(D), NSK} || {NSK, _} <- NewKeys, D <- EvictedAddrs], + ToRemoveAddrs = [ + {remove, DevAddrToInt(D), NSK, MaxCopies} + || {NSK, _} <- NewKeys, D <- EvictedAddrs + ], %% add the new devaddr, nskwkey. <> = lorawan_utils:reverse(NewDevAddr), - Updates = lists:usort([{add, DevAddrInt, NwkSKey}] ++ ToRemoveKeys ++ ToRemoveAddrs), + Updates = lists:usort([{add, DevAddrInt, NwkSKey, MaxCopies}] ++ ToRemoveKeys ++ ToRemoveAddrs), ok = router_ics_skf_worker:update(Updates), lager:debug("sending update skf for join ~p ~p", [Updates]), @@ -1760,34 +1773,8 @@ validate_frame_(PacketFCnt, Packet, PubKeyBin, HotspotRegion, Device0, OfferCach PHash :: binary(), OfferCache :: map() ) -> {ok, non_neg_integer(), non_neg_integer()} | {error, any()}. -maybe_charge(Device, PayloadSize, PubKeyBin, PHash, OfferCache) -> - case maps:get({PubKeyBin, PHash}, OfferCache, undefined) of - undefined -> - case charge_when_no_offer() of - false -> - Metadata = router_device:metadata(Device), - {Balance, Nonce} = - case maps:get(organization_id, Metadata, undefined) of - undefined -> - {0, 0}; - OrgID -> - router_console_dc_tracker:current_balance(OrgID) - end, - {ok, Balance, Nonce}; - true -> - router_console_dc_tracker:charge(Device, PayloadSize) - end; - _ -> - router_console_dc_tracker:charge(Device, PayloadSize) - end. - --spec charge_when_no_offer() -> boolean(). -charge_when_no_offer() -> - case application:get_env(router, charge_when_no_offer, true) of - "true" -> true; - true -> true; - _ -> false - end. +maybe_charge(Device, PayloadSize, _PubKeyBin, _PHash, _OfferCache) -> + router_console_dc_tracker:charge(Device, PayloadSize). %%%------------------------------------------------------------------- %% @doc diff --git a/src/grpc/router_ics_skf_worker.erl b/src/grpc/router_ics_skf_worker.erl index 1e74a1ffc..862469e4e 100644 --- a/src/grpc/router_ics_skf_worker.erl +++ b/src/grpc/router_ics_skf_worker.erl @@ -149,7 +149,14 @@ startup_reconcile() -> %% Worker API %% ------------------------------------------------------------------ --spec update(Updates :: list({add | remove, non_neg_integer(), binary()})) -> +-spec update( + Updates :: list({ + add | remove, + DevaddrInt :: non_neg_integer(), + NwkSKey :: binary(), + MultiBuy :: non_neg_integer() + }) +) -> ok. update([]) -> ok; @@ -202,11 +209,16 @@ diff_skf_to_updates(#{remote := _, local := _} = Diff) -> (skfs()) -> skf_updates(). skf_to_add_update(SKFs) when erlang:is_list(SKFs) -> lists:map(fun skf_to_add_update/1, SKFs); -skf_to_add_update(#iot_config_skf_v1_pb{devaddr = Devaddr, session_key = SessionKey}) -> +skf_to_add_update(#iot_config_skf_v1_pb{ + devaddr = Devaddr, + session_key = SessionKey, + max_copies = MaxCopies +}) -> #iot_config_route_skf_update_v1_pb{ action = add, devaddr = Devaddr, - session_key = SessionKey + session_key = SessionKey, + max_copies = MaxCopies }. -spec skf_to_remove_update @@ -214,11 +226,16 @@ skf_to_add_update(#iot_config_skf_v1_pb{devaddr = Devaddr, session_key = Session (skfs()) -> skf_updates(). skf_to_remove_update(SKFs) when erlang:is_list(SKFs) -> lists:map(fun skf_to_remove_update/1, SKFs); -skf_to_remove_update(#iot_config_skf_v1_pb{devaddr = Devaddr, session_key = SessionKey}) -> +skf_to_remove_update(#iot_config_skf_v1_pb{ + devaddr = Devaddr, + session_key = SessionKey, + max_copies = MaxCopies +}) -> #iot_config_route_skf_update_v1_pb{ action = remove, devaddr = Devaddr, - session_key = SessionKey + session_key = SessionKey, + max_copies = MaxCopies }. %% ------------------------------------------------------------------ @@ -271,11 +288,12 @@ handle_cast( fun (#iot_config_route_skf_update_v1_pb{} = Update) -> Update; - ({Action, Devaddr, Key}) -> + ({Action, Devaddr, Key, MaxCopies}) -> #iot_config_route_skf_update_v1_pb{ action = Action, devaddr = Devaddr, - session_key = binary:encode_hex(Key) + session_key = binary:encode_hex(Key), + max_copies = MaxCopies } end, Updates0 @@ -384,6 +402,7 @@ get_local_skfs(RouteID) -> lists:usort( lists:filtermap( fun(Device) -> + MultiBuy = maps:get(multi_buy, router_device:metadata(Device), 0), case { router_device:is_active(Device), @@ -403,7 +422,8 @@ get_local_skfs(RouteID) -> {true, #iot_config_skf_v1_pb{ route_id = RouteID, devaddr = DevAddr, - session_key = erlang:binary_to_list(binary:encode_hex(SessionKey)) + session_key = erlang:binary_to_list(binary:encode_hex(SessionKey)), + max_copies = MultiBuy }} end end, diff --git a/test/router_ics_skf_worker_SUITE.erl b/test/router_ics_skf_worker_SUITE.erl index 8875b430e..90c06e199 100644 --- a/test/router_ics_skf_worker_SUITE.erl +++ b/test/router_ics_skf_worker_SUITE.erl @@ -111,7 +111,8 @@ main_test(Config) -> ok = router_test_ics_route_service:add_skf(#iot_config_skf_v1_pb{ route_id = ?ROUTE_ID, devaddr = 0, - session_key = [] + session_key = [], + max_copies = 42 }), %% Trigger a reconcile @@ -243,18 +244,20 @@ device_to_skf(RouteID, Device) -> #iot_config_skf_v1_pb{ route_id = RouteID, devaddr = binary:decode_unsigned(router_device:devaddr(Device), little), - session_key = erlang:binary_to_list(binary:encode_hex(router_device:nwk_s_key(Device))) + session_key = erlang:binary_to_list(binary:encode_hex(router_device:nwk_s_key(Device))), + max_copies = maps:get(multi_buy, router_device:metadata(Device), 999) }. create_n_devices(N) -> lists:map( - fun(_X) -> + fun(Idx) -> ID = router_utils:uuid_v4(), {ok, Devaddr} = router_device_devaddr:allocate(no_device, undefined), router_device:update( [ {devaddrs, [Devaddr]}, - {keys, [{crypto:strong_rand_bytes(16), crypto:strong_rand_bytes(16)}]} + {keys, [{crypto:strong_rand_bytes(16), crypto:strong_rand_bytes(16)}]}, + {metadata, #{multi_buy => Idx}} ], router_device:new(ID) ) diff --git a/test/router_test_ics_route_service.erl b/test/router_test_ics_route_service.erl index 1abbc010c..52d372697 100644 --- a/test/router_test_ics_route_service.erl +++ b/test/router_test_ics_route_service.erl @@ -211,13 +211,15 @@ update_skfs(Ctx, Req) -> #iot_config_route_skf_update_v1_pb{ action = Action, devaddr = Devaddr, - session_key = SessionKey + session_key = SessionKey, + max_copies = MaxCopies } ) -> SKF = #iot_config_skf_v1_pb{ devaddr = Devaddr, session_key = SessionKey, - route_id = RouteID + route_id = RouteID, + max_copies = MaxCopies }, case Action of add -> add_skf(SKF);