Skip to content

Commit

Permalink
Merge pull request msantos#37 from shun159/feature/mpls
Browse files Browse the repository at this point in the history
Add MPLS codec
  • Loading branch information
msantos authored Jul 15, 2016
2 parents 1ed6013 + 30a99ed commit c19e086
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 1 deletion.
1 change: 1 addition & 0 deletions include/pkt.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
-include("pkt_802_1q.hrl").
-include("pkt_arp.hrl").
-include("pkt_lldp.hrl").
-include("pkt_mpls.hrl").

-include("pkt_gre.hrl").
-include("pkt_icmp6.hrl").
Expand Down
2 changes: 2 additions & 0 deletions include/pkt_ether.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
-define(ETH_P_802_1Q, 16#8100).
-define(ETH_P_802_1QinQ, 16#88a8).
-define(ETH_P_LLDP, 16#88CC).
-define(ETH_P_MPLS_UNI, 16#8847).
-define(ETH_P_MPLS_MULTI, 16#8848).

-record(ether, {
dhost = <<0,0,0,0,0,0>> :: <<_:48>>,
Expand Down
32 changes: 32 additions & 0 deletions include/pkt_mpls.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-define(MPLS_LABEL_IPV4NULL, 0).
-define(MPLS_LABEL_RTALERT, 1).
-define(MPLS_LABEL_IPV6NULL, 2).
-define(MPLS_LABEL_IMPLNULL, 3).
-define(MPLS_LABEL_ENTROPY, 7).
-define(MPLS_LABEL_GAL, 13).
-define(MPLS_LABEL_OAMALERT, 14).
-define(MPLS_LABEL_EXTENSION, 15).
-define(MPLS_LABEL_FIRST_UNRESERVED, 16).

%% Reference: RFC 5462, RFC 3032
%%
%% 0 1 2 3
%% 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
%% | Label | TC |S| TTL |
%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
%%
%% Label: Label Value, 20 bits
%% TC: Traffic Class field, 3 bits
%% S: Bottom of Stack, 1 bit
%% TTL: Time to Live, 8 bits
%%

-record(shim, {label = 0 :: 1..16#fffff,
tc = 0 :: 1..7,
s = true :: boolean(),
ttl = 0 :: pkt:uint8_t()}).
-type shim() :: #shim{}.

-record(mpls, {labels = [] :: [shim()]}).
-type mpls() :: #mpls{}.
8 changes: 8 additions & 0 deletions src/pkt.erl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
makesum/1,
ether/1,
ether_type/1,
mpls/1,
'802.1q'/1,
llc/1,
arp/1,
Expand Down Expand Up @@ -117,6 +118,9 @@ decapsulate_next({linux_cooked, Data}, Headers) ->
decapsulate_next({ether, Data}, Headers) ->
{Header, Payload} = ether(Data),
decapsulate_next({next(Header), Payload}, [Header|Headers]);
decapsulate_next({mpls, Data}, Headers) ->
{Header, Next, Payload} = mpls(Data),
decapsulate_next({Next, Payload}, [Header|Headers]);
decapsulate_next({'802.1q', Data}, Headers) ->
{Header, Payload} = '802.1q'(Data),
decapsulate_next({next(Header), Payload}, [Header|Headers]);
Expand Down Expand Up @@ -296,6 +300,10 @@ ether(N) ->
ether_type(N) ->
pkt_ether:type(N).

%% MPLS
mpls(N) ->
pkt_mpls:codec(N).

%% ARP
arp(N) ->
pkt_arp:codec(N).
Expand Down
5 changes: 4 additions & 1 deletion src/pkt_ether.erl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ type(EtherType) when EtherType < 16#05DC -> llc;
%% 802.1Q Virtual LAN
type(?ETH_P_802_1Q) -> '802.1q';
%% 802.1ad (802.1q QinQ)
type(?ETH_P_802_1QinQ) -> '802.1qinq'.
type(?ETH_P_802_1QinQ) -> '802.1qinq';
%% MPLS_
type(?ETH_P_MPLS_UNI) -> mpls;
type(?ETH_P_MPLS_MULTI) -> mpls.

codec(<<Dhost:6/bytes, Shost:6/bytes, Type:16, Payload/binary>>) ->
% Len = byte_size(Packet) - 4,
Expand Down
29 changes: 29 additions & 0 deletions src/pkt_mpls.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
-module(pkt_mpls).

-include("pkt_mpls.hrl").

-export([codec/1]).

codec(Mpls) when is_binary(Mpls) ->
decode(Mpls, []);
codec(#mpls{labels = Labels}) ->
encode(Labels, <<>>).

decode(<<L:20, Tc:3, 1:1, Ttl:8, Rest/binary>>, Labels0) ->
Mpls = #shim{label = L, tc = Tc, s = true, ttl = Ttl},
Labels = #mpls{labels = lists:reverse([Mpls|Labels0])},
{Next, Payload} = next_header(Rest),
{Labels, Next, Payload};
decode(<<L:20, Tc:3, 0:1, Ttl:8, Rest/binary>>, Labels0) ->
Mpls = #shim{label = L, tc = Tc, s = false, ttl = Ttl},
decode(Rest, [Mpls|Labels0]).

encode([], Bin) -> Bin;
encode([#shim{label = L, tc = Tc, s = true, ttl = Ttl}|_], Bin) ->
<<Bin/bytes, L:20, Tc:3, 1:1, Ttl:8>>;
encode([#shim{label = L, tc = Tc, s = false, ttl = Ttl}|Rest], Bin) ->
encode(Rest, <<L:20, Tc:3, 0:1, Ttl:8, Bin/bytes>>).

next_header(<<>>) -> {none, <<>>};
next_header(<<4:4, _/bitstring>> = Binary) -> {ipv4, Binary};
next_header(<<6:4, _/bitstring>> = Binary) -> {ipv6, Binary}.
112 changes: 112 additions & 0 deletions test/pkt_mpls_tests.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
-module(pkt_mpls_tests).

-include_lib("pkt/include/pkt.hrl").
-include_lib("eunit/include/eunit.hrl").

codec_test_() ->
[decode_single_tagging(),
decode_double_tagging()].

decode_single_tagging() ->
Frame = pkt:decapsulate(single()),
[#ether{dhost = <<194,5,99,77,0,0>>,
shost = <<194,3,99,62,0,0>>,
type = 34887,crc = 0},
#mpls{labels = [#shim{label = 18,
tc = 0,
s = true,
ttl = 254}]},
#ipv4{v = 4,
hl = 5,
tos = 0,
len = 100,
id = 25,
df = 0,mf = 0,
off = 0,
ttl = 254,
p = 1,
sum = 2349,
saddr = {192,168,10,1},
daddr = {192,168,40,1},
opt = <<>>},
#icmp{type = 8,
code = 0,checksum = 28057,id = 5,
sequence = 0,
gateway = {127,0,0,1},
un = <<0,0,0,0>>,
mtu = 0,
pointer = 0,
ts_orig = 0,
ts_recv = 0,
ts_tx = 0},
_] = Frame.

decode_double_tagging() ->
Frame = pkt:decapsulate(double()),
[#ether{dhost = <<0,48,150,230,252,57>>,
shost = <<0,48,150,5,40,56>>,
type = 34887,crc = 0},
#mpls{labels = [#shim{label = 18,tc = 0,s = false,ttl = 255},
#shim{label = 16,tc = 0,s = true,ttl = 255}]},
#ipv4{v = 4,
hl = 5,
tos = 0,
len = 100,
id = 80,
df = 0,
mf = 0,
off = 0,
ttl = 255,
p = 1,
sum = 42758,
saddr = {10,31,0,1},
daddr = {10,34,0,1},
opt = <<>>},
#icmp{type = 8,
code = 0,
checksum = 48401,
id = 3941,
sequence = 4768,
gateway = {127,0,0,1},
un = <<0,0,0,0>>,
mtu = 0,
pointer = 0,
ts_orig = 0,
ts_recv = 0,
ts_tx = 0},
_] = Frame.

single() ->
<<16#c2, 16#05, 16#63, 16#4d, 16#00, 16#00, 16#c2, 16#03,
16#63, 16#3e, 16#00, 16#00, 16#88, 16#47, 16#00, 16#01,
16#21, 16#fe, 16#45, 16#00, 16#00, 16#64, 16#00, 16#19,
16#00, 16#00, 16#fe, 16#01, 16#09, 16#2d, 16#c0, 16#a8,
16#0a, 16#01, 16#c0, 16#a8, 16#28, 16#01, 16#08, 16#00,
16#6d, 16#99, 16#00, 16#05, 16#00, 16#00, 16#00, 16#00,
16#00, 16#00, 16#00, 16#24, 16#10, 16#88, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd>>.

double() ->
<<16#00, 16#30, 16#96, 16#e6, 16#fc, 16#39, 16#00, 16#30,
16#96, 16#05, 16#28, 16#38, 16#88, 16#47, 16#00, 16#01,
16#20, 16#ff, 16#00, 16#01, 16#01, 16#ff, 16#45, 16#00,
16#00, 16#64, 16#00, 16#50, 16#00, 16#00, 16#ff, 16#01,
16#a7, 16#06, 16#0a, 16#1f, 16#00, 16#01, 16#0a, 16#22,
16#00, 16#01, 16#08, 16#00, 16#bd, 16#11, 16#0f, 16#65,
16#12, 16#a0, 16#00, 16#00, 16#00, 16#00, 16#00, 16#53,
16#9e, 16#e0, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd, 16#ab, 16#cd,
16#ab, 16#cd>>.

0 comments on commit c19e086

Please sign in to comment.