TCPIP Stack Dev PartB
TCPIP Stack Dev PartB
TCP/IP Stack
1. Interface Management & statistics
Part B
2. Dynamic L3 Route Calculation
No More Manual installation of L3 routes
➢ Timer management
➢ Logging Infrastructure
➢ Appln Development
➢ Event Notification
TCP/IP Stack Project -> Interface Management
➢ Interface Management :
➢ Gathering Tx & Rx Statistics per Device’s interfaces
➢ Interface Disable/Enable Or up/down
➢ Creating/Updating Configuration per interfaces
➢ Notifying interface status to interested parties (applications etc ..)
➢ Network Applications need to react to Interface Config change
➢ This Course will push our TCP/IP Stack library developed in Part - A from being static towards dynamic .. .!
➢ Real World Demo . .
TCP/IP Stack Project -> Interface Management -> Interface Enable/Disable Problem Statement
➢ A Typical Routing Device allows the provision to admin to Enable or disable the interface of a
Network Device
➢ Do not send out any data/traffic (discards the outbound traffic just before it is placed on wire)
➢ Discards all data / traffic as soon as recvd (at physical layer itself)
Application
Transport Layer
Physical Layer
TCP/IP Stack Project -> Interface Management -> Interface Enable/Disable-> Code Changes
➢ Config CLI :
nwcli.c Data Structure Changes :
config node <node-name> interface <if-name> <if-up-down>
typedef struct intf_nw_props_ {
tcp-ip-project> config-node-H1-interface-eth1 $ ?
Parse Success. /*L1 Properties*/
nxt leaf -> STRING | <up | down> bool_t is_up;
...
Add the handler case in intf_config_handler(. . .) ...
➢ Functional Changes
➢ Testing
➢ A Typical Routing Device allows the provision to admin to Check Send & Recv Statistics per interface of a
Network Device
➢ Send Statistics :
➢ Number of Network Packets sent out of the interface
➢ Recv Statistics
➢ Number of Packets Recvd on an interface
Application
Transport Layer
Physical Layer
TCP/IP Stack Project -> Interface Management -> Interface Send/Recv Statistics
➢ CLI :
nwcli.c
show node <node-name> interface statistics
(must show send and recv counters of all interfaces of a device)
S B D
eths2 Lo : [Link]
UDP : 2003
L
pkt_gen.c • Feed the pkt into S as if S is receiving
the pkts on its local intf eths2
• S’s TCP/IP stack then process the pkt
as per the pkt headers
A
➢ So far, we have been using ping to test the new feature we implement in TCP/IP stack
➢ Instead, now we write a pkt generator - small separate program which would feed stream of pkts into our TCP/IP stack
➢ Terminology :
➢ Pseudo TCP/IP Stack - Our TCP/IP stack Library
➢ Actual TCP/IP Stack - The Actual TCP/IP Stack running on your local machine in kernel space
TCP/IP Stack Project -> Packet generator
S B D
eths2 Lo : [Link]
UDP : 2003
L
pkt_gen.c
➢ We want to generate stream of pkts : S sends Pseudo ICMP packet to Destination D with dest ip address : [Link]
➢ Equivalent to run node S ping [Link]
➢ pkt_gen.c is a simple UDP program which generate and sends UDP packets
➢ Revise how we implemented the packet exchange infrastructure in Part-A
TCP/IP Stack Project -> Packet generator
[Link]
(Recap) eths2
Actual Hdrs for actual TCP/IP Stack Pkt for our Simulated TCP/IP stack
This is just a UDP payload for actual TCP/IP Stack
TCP/IP Stack Project -> Actual and Pseuodo Headers
Actual Hdrs for actual TCP/IP Stack Pkt for our Simulated TCP/IP stack
This is just a UDP payload for actual TCP/IP Stack
Dst mac =Stack
TCP/IP 0 Proto = UDP-> Packet
Project Dstgenerator
port = 2001 Aux Info : eths2 Dst mac = oxFF Proto = ICMP FCS = 0 FCS =
Src mac = 0 ttl = 64 Src port = 0 Src mac = 0 ttl = 64 <some
Type = Src ip = [Link] Type = ox0800 Src ip = [Link] actual Actual
ox0800 Dst ip = [Link] Dst ip = [Link] value>
pkt
Actual Hdrs for actual TCP/IP Stack Pkt for our Simulated TCP/IP stack
Steps :
1. Create UDP socket
int udp_sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP );
2. Prepare packet
Aux info + Pseudo headers
➢ We love our TCP/IP Stack library ☺, so, let us improve its functionality
➢ By now, you must have realized, every time we need to install L3 routes in L3 devices manually
➢ Demo … !
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table
Pre-Requisites
➢ Pls complete Appendix section A.1 and A.2 to cover up theory behind construction of L3 routing table
➢ In these Appendix Section, I cover topics from the point of getting conceptual understanding, and not understanding
implementation details
➢ Once you complete these Appendix Section, We shall be in a position to actually implement it
➢ From next lecture Video, I presume, you have the concept clarity on Routing Table Construction Algorithm and
approach, We will discuss implementation straight away
➢ This will probably first time you would realize how Networking biased algorithms are implemented
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table
➢ We will be going to add SPF algorithm to our TCP/IP stack library as a new application
➢ It would mean, SPF algorithm implementation shall be an extension to our TCP/IP stack library and not a
core part of it
➢ We shall be going to develop several other applications on top of our TCP/IP stack library in plugin-play model
➢ This would NOT require us to change/update TCP/IP stack lib core code in anyway
Getting Started
➢ Creating new Spf algo Application files and folders in the project code
Preparation
➢ Before we write any code to implement SPF algo, we need to do some groundwork :
➢ Every node would have a data structure which would store all information related to spf algorithm
➢ Example Snapshot :
Lo : [Link] Lo : [Link] Lo : [Link]
typedef struct nexthop_{ R1 R2 R3
eth0 eth1 eth2 eth3
char gw_ip[16]; 3 [Link]/24 [Link]/24 [Link]/24 [Link]/24
interface_t *oif; eth7 eth3
uint32_t ref_count; [Link]/24 [Link]/24
} nexthop_t;
[Link] [Link]
NH1 = R1-eth0 NH2 = R1-eth7
0 0 eth6 eth5
[Link]/24 [Link]/24
R4
Lo: [Link]
R2 R4 R3
10 10 20 Result of
R1 as spf root
node->spf_data-> NH1 NH2 NH1, NH2 compute_spf(R1)
spf_result_head
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Helper APIs
➢ We need to write some Helper APIs (arnd 10) which would make it easier to implement Spf algo
➢ You must thoroughly test these APIs before actually start using them .. Otherwise Nightmare !
➢ You can write a small driver program to test the APIs you will write Or Cross check against partB soln code base
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Helper APIs
API 1 :
net.h/.c
R1 R2
bool_t eth0 L eth1
is_interface_l3_bidirectional (interface_t *interface); /*ptr to R1-eth0*/ [Link]/24 [Link]/24
API 2 :
spf.c void
spf_flush_nexthops (nexthop_t **nexthop){
void int i = 0;
spf_flush_nexthops(nexthop_t **nexthop);
Eg : spf_flush_nexthops (node->spf_data->nexthops); if(!nexthop) return;
spf_flush_nexthops (spf_result->nexthops);
for( ; i < MAX_NXT_HOPS; i++){
if(nexthop[i]){
assert(nexthop[i]->ref_count);
nexthop[i]->ref_count - = 1;
if (nexthop[i]->ref_count == 0){
free(nexthop[i]);
}
nexthop[i] = NULL;
}
}
}
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Helper APIs
API 3 :
spf.c
API 4 :
spf.c
typedef struct nexthop_{
static nexthop_t *
create_new_nexthop (interface_t *oif) { /*ptr to S-eth0*/
char gw_ip[16];
nexthop_t *nexthop = calloc(1, sizeof(nexthop_t)); interface_t *oif;
nexthop->oif = oif; uint32_t ref_count;
interface_t *other_intf = &oif->link->intf1 == oif ? \ } nexthop_t;
&oif->link->intf2 : &oif->link->intf1;
if(!other_intf){
free(nexthop);
return NULL; spf_root S R2
} eth0 L eth1
strncpy(nexthop->gw_ip, IF_IP(other_intf), 16); [Link]/24 [Link]/24
nexthop->ref_count = 0;
return nexthop;
}
Nh = { [Link] , ptr to S-eth0, 0 }
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Helper APIs
API 5 :
spf.c API6 :
spf.c
static bool_t
spf_insert_new_nexthop(nexthop_t **nexthop_arry, static bool_t
nexthop_t *nxthop) { spf_is_nexthop_exist(nexthop_t **nexthop_array,
nexthop_t *nxthop){
int i = 0;
int i = 0;
for( ; i < MAX_NXT_HOPS; i++){
for( ; i < MAX_NXT_HOPS; i++){
if(nexthop_arry[i]) continue;
nexthop_arry[i] = nxthop;
if (!nexthop_array[i])
nexthop_arry[i]->ref_count++;
return FALSE;
return TRUE;
}
if (nexthop_array[i]->oif == nxthop->oif)
return FALSE;
return TRUE;
} }
return FALSE;
}
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Helper APIs
API 7 :
spf.c
/* Copy all nexthops of src to dst, do not copy which are already
* present*/
static int
spf_union_nexthops_arrays(nexthop_t **src, nexthop_t **dst);
API 8 :
spf.c
API to compare two spf_data_t objects
/*Return -1 , 0 or 1 */
static int
spf_comparison_fn(void *data1, void *data2){
This API is used as a fn pointer to PQ API
spf_data_t *spf_data_1 = (spf_data_t *)data1;
spf_data_t *spf_data_2 = (spf_data_t *)data2; PQ will use this function to insert a new spf_data
object in PQ as per the priority (spf_metric)
if(spf_data_1->spf_metric < spf_data_2->spf_metric)
return -1;
if(spf_data_1->spf_metric > spf_data_2->spf_metric)
return 1; Reference :
return 0; typedef struct spf_data_{
} ...
/*Temp fields used for calculations*/
uint32_t spf_metric;
...
} spf_data_t;
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Helper APIs
API 9 :
spf.c
API to look up spf_result_t object from spf result list of spf_root using node ptr as lookup key
static spf_result_t *
spf_lookup_spf_result_by_node(node_t *spf_root, node_t *node){
glthread_t *curr;
spf_result_t *spf_result;
spf_data_t *curr_spf_data;
ITERATE_GLTHREAD_BEGIN(&spf_root->spf_data->spf_result_head, curr){
spf_result = spf_res_glue_to_spf_result(curr);
if(spf_result->node == node)
return spf_result;
} ITERATE_GLTHREAD_END(&spf_root->spf_data->spf_result_head, curr);
return NULL;
R2 R4 R3
}
10 10 20
spf_root->spf_data-> NH1 NH2 NH1, NH2
spf_result_head
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Helper APIs
API 10 :
spf.c
Short-hand Macros :
➢ Initialization
➢ Insertion
➢ Deletion
➢ Dequeue
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> PQ Mgmt
Reference :
typedef struct spf_data_{
node_t *node;
glthread_t spf_result_head;
uint32_t spf_metric;
glthread_t priority_thread_glue;
nexthop_t *nexthops[MAX_NXT_HOPS];
} spf_data_t;
➢Initialization Phase 1
➢Step 1, 2 and 3
➢Execution Phase 2
➢Step 4, 5 and 6
Initialization : Part 1
For Node • Initialize Metrics
N
N, spf_data calloc spf_data • delete old spf results if any
exist ? • Remove Nodes from PQ
• Flush Nexthops if any
Y
void
init_node_spf_data (node_t *node,
N bool_t delete_spf_result);
N ==
spf_root 1
8
4
A B
Y 3
0
10
delete old spf_result list S 5
4
6
D C
8
Init spf_metric = INFINITE
Remove node N from PQ
Flush nexthops
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Initialization Phase
Next-hop Calculation
spf_root S R2 spf_root S R2
eth0 L1(5) eth1
eth0 L eth1 [Link]/24 [Link]/24
[Link]/24 [Link]/24 eth1 L2(5) eth0
[Link]/24 [Link]/24
Nh = { [Link] , ptr to S-eth0, 0 }
Nh1 = { [Link] , ptr to S-eth0, 0 }
Nh2 = { [Link] , ptr to S-eth1, 0 }
spf_root S R2
eth0 L1(5) eth1
[Link]/24 [Link]/24 The nexthops computed by spf root are stored in
eth1 L2(10) eth0 Nbr’s spf_data->nexthops[ ] array
[Link]/24 [Link]/24
Nexthop Eligibility
Nh = { [Link] , ptr to S-eth1, 0 } is_interface_l3_bidirectional( )
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Initialization Phase
Example
A->spf_data->nexthops
NH1 : [S-eth1, [Link], 0 ]
NH2 : [S-eth2, [Link], 0 ]
A
A->spf_data->spf_metric = 3
eth4
[Link]
B->spf_data->nexthops
B NH1 : [S-eth4, [Link], 0 ]
B->spf_data->spf_metric = 6
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Initialization Phase
For each NH = (Nbr, oif, Gw) of NH1 : [S-eth1,
8
spf_root [Link], 0 ] 4
A B
3
0
10
S 5
Is NH N Explore 4
eligible next NH 6
? D C
NH2 : [S-eth2,
8
N [Link], 0 ]
Y
2.2 spf_flush_nexthops(
2.1 Nbr->spf_data->nexthops)
link_cost(oif) link_cost(oif) NH = create_new_nexthop(oif);
N Y spf_insert_new_nexthop(
< ==
SPF_METR SPF_METR Nbr->spf_data->nexthops,
IC (Nbr) ? IC (Nbr) ? NH)
SPF_METRIC(nbr) = get_link_cost(oif);
Y
Initialization : Part 2
Initialize direct nexthops of spf root
spf_flush_nexthops(Nbr->spf_data->nexthops)
NH = create_new_nexthop(oif);
spf_insert_new_nexthop( void
Nbr->spf_data->nexthops, NH) initialize_direct_nbrs (node_t *spf_root);
SPF_METRIC(nbr) = get_link_cost(oif);
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Initialization Phase
Looping Macro
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Initialization Phase
glthread_t priority_lst;
init_glthread(&priority_lst); Initialization: Part 3
3 Initialize Priority Queue
Add Spf_root in PQ
glthread_priority_insert (&priority_lst,
&spf_root->spf_data->priority_thread_glue,
spf_comparison_fn,
spf_data_offset_from_priority_thread_glue);
8
NH1 : [S-eth1,
[Link], 0 ]
4
PQ = { S } A B
3
0
10
S 5
4
6
D C
NH2 : [S-eth2,
8
[Link], 0 ]
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> CLI Requirements
➢ Now that we have finished implementation of Core SPF Algorithm, Let us test it before proceeding forward
➢ File : spf.c
spf_record_result( )
N
Is PQ
N = dequeue_glthread_first(PQ)
Empty ?
➢ Remove Y from PQ if present, and add it back to PQ nh1, nh2 nh1, nh3
➢ Cost(y) = Cost(x) + m
ECMP case
SPF_METRIC SPF_METRIC
(Curr_N) + (Curr_N) +
spf_union_nexthops_arrays(
link_cost(Curr_N, link_cost(Curr_N,
Curr_N->spf_data->nexthops,
Nbr) < Nbr) ==
N Y Nbr->spf_data->nexthops);
SPF_METRIC SPF_METRIC
(Nbr) (Nbr) 6.2
N
Y
spf_flush_nexthops(Nbr->spf_data->nexthops); Continue
spf_union_nexthops_arrays(
curr_node->spf_data->nexthops,
nbr->spf_data->nexthops);
SPF_METRIC(Nbr) = SPF_METRIC(Curr_N) +
get_link_cost(Curr_N, Nbr); 6.1 spf_flush_nexthops(Curr_N->spf_data->nexthops);
Remove Nbr from PQ if present
When all Nbrs of Curr_N are processed
Add back Nbr in PQ
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Testing
➢ It is important that we test our implementation of SPF algorithm on various different topologies and verify the correctness
of the output before proceeding forward
➢ In addition, change topologies using various existing CLIs as below, and trigger run spf all and
verify all nodes update their spf results
➢ conf node <node-name> interface <if-name> metric <metric-val>
➢ conf node <node-name> interface <if-name> [up | down]
➢ Attached is the document which shows the topologies you need to be build and testing procedure
➢ Pls follow the instructions against each Test in the document
➢ Proceed to next section only when you have verified that your SPF implementation reveals correct output in all cases
➢ Fix the bugs/anomalies if any
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Route Calculation
➢ We will use the output produced by SPF algorithm for final Routing table calculation of SPF root node
➢ We need to implement fn :
➢ But before that, we need to make some minor code changes to make our Routing Table and
L3 routes ECMP aware
TCP/IP Stack Project -> ECMP Support
R1’s RT entry
[Link]/32 [Link] eth0 2 build_square_topo( )
[Link] eth7
Lo : [Link] Lo : [Link] Lo : [Link]
R1 R2 R3
RT Table / L3 route data structure must allow
eth0 eth1 eth2 eth3
a provision to allow multiple nexthops [Link]/24 [Link]/24 [Link]/24 [Link]/24
associated with an L3 route eth7 eth3
[Link]/24 [Link]/24
Implementing ECMP
Current : New :
Update clear_rt_table( ) to free the nexthops first before freeing the route, else it will cause mem leak
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Route Calculation
New :
• nxthop_idx - points to the nexthop which will be used by the route to forward the next pkt
• Every time the route forwards the pkt, nxthop_idx is incremented to point to the next nexthop in array
• Route forwards the pkt P1,P2,P3,P4,P5… using nexthops NH3,NH4,NH1,NH2,NH3…
• Update Functions : layer3_ip_pkt_recv_from_layer2( ) & demote_packet_to_layer3 ( ) to use new API to retrieve the
forwarding nexthop of the route
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Spf Algorithm -> Route Calculation
int
spf_install_routes(node_t *spf_root);
Spf_root S
SPF Algo Result Final Routing Table of Spf Root S
Dest Node Oif Gateway cost Nexthop Dest Address Oif Gateway cost Nexthop
Replace Dest Nodes
A eth1 [Link] 3 A With their loop-back [Link]/32 eth1 [Link] 3 A
Address
D eth2 [Link] 4 D [Link]/32 eth2 [Link] 4 D
B eth1 [Link] 7 A [Link]/32 eth1 [Link] 7 A
C eth2 [Link] 10 D [Link]/32 eth2 [Link] 10 D
TCP/IP Stack Project -> Dynamic Construction of L3 Routing Table -> Routing Table Calculation on Startup
➢ For example:
➢ We want L3 Routing Tables get populated automatically as soon as we start our project
➢ User should not be compelled to run “run spf all” on project start up to populate RTs
➢ Our TCP/IP Stack library could be used to implement more new Network protocols which would generate their own
Network packets (Application headers)
➢ The common way of debugging and troubleshooting networks is to analyse what packets are being sent or recvd by node(s)
of the topology
➢ On real devices, we have tools to capture and analyze packet contents flowing across the network
➢ Tcpdump
➢ Wireshark
➢ For our Emulated TCP/IP stack library, standard tools would not likely to work and we would like to develop the way
our TCP/IP stack library could emit out what packets are in flows across the network
➢ Lets start . .
TCP/IP Stack Project -> Logging Infra -> Working Demo
Goals :
➢ User should have a choice whether he wants to enable logging for only sent or only recv pkts or both
➢ Extra : User should have a choice whether he wants to enable logging for some selective interfaces of a node
➢ New Files :
tcpip_stack/tcp_ip_trace.c
tcpip_stack/tcp_ip_trace.h
➢ Explore use of sprint/snprintf from internet. We would be using this fn extensively for logging
➢ Let us first brainlessly write all required APIs first, then we shall see how to use the APIs for logging and control logging
using CLIs
TCP/IP Stack Project -> Logging Infra -> logging APIs hierarchy
➢ First, we need set of APIs to format the headers of various types into buffer
void tcp_dump( )
void tcp_dump( )
void tcp_write_data( )
static void
tcp_dump (int sock_fd, << if 0 then formatted pkt contents shall be written to console, -1 otherwise
FILE *log_file1, << Node level Log file ptr into where formatted pkt contents shall be w
Fn to parse the pkt FILE *log_file2, << Per interface level Log file ptr into where formatted pkt contents shall be writt
and prepare formatted char *pkt, << Pkt pointer to parse
output in buffer memory uint32_t pkt_size, << pkt size
hdr_type_t hdr_type, << Starting hdr type of the pkt
char *out_buff, << output buffer into which the formatted pkt content would b
uint32_t write_offset, << starting position in output buffer to write formatted pkt content
uint32_t out_buff_size); << size of output buffer in bytes
TCP/IP Stack Project -> Logging Infra -> logging hierarchy
void tcp_dump( )
void tcp_write_data( )
static void
tcp_write_data (int sock_fd, << 0 to emit on console, -1 otherwise
Fn to write the formatted pkt content
FILE *log_file1, << Node’s log file to write formatted pkt content
to output source(s)
FILE *log_file2, << NULL
: Console
char *out_buff, << Buffer which contains formatted output
: log file(s)
uint32_t buff_size) << Size of contents in the buffer in bytes
TCP/IP Stack Project -> Logging Infra -> CLIs for logging
Added As Assignment
Notify the Subscribers about the events !
Notification Chains
➢ Notification Chains is an architectural concept used to notify multiple subscribers interested in the particular event
➢ A party which generates an Event is called Publisher, and parties which are interested in being notified of the event
are called subscribers
➢ Once the Event is generated/produced by the Publisher, the Event is pushed to Subscriber(s)
➢ Subscriber can register and de-register for the event at their will
➢ An Application ( = spf algo as an example ) must react to certain common configuration changes or events
happening on a networking device
➢ We need a mechanism that whenever an admin change such common interface level config, then all interested
application must be notified of this change so that they can take appropriate action
Conclusion : Individual Applications must be notified of generic config change done by admin, We would achieve this
through notification chains, a mechanism to distribute events
TCP/IP Stack Project -> Notification Chains
Plan :
Transport Layer
➢ Design : nwcli.c
Network Layer
➢ NCM is nothing but a linked list of
callbacks registered by applications I1
I2
Notification Data link layer
Chains
➢ On Interface config change, we will iterate over this Module
linked list and invoke all callbacks Physical Layer
Subscribers
App1 App2 App3 App4
Publisher
Fa1() Fa2() Fa3() Fa4()
[Link]/32 [Link] eth0 1
[Link]/32 [Link] eth1 1
[Link]/32 [Link] eth1 1
[Link]/32 [Link] eth1 1
➢ Subscribers have registered their callbacks with the publishers against the entries which they are
interested in
➢ Whenever publisher update the entry in its routing table, it iterates over NFC and invoke callbacks of
Subscribers matching the entry
➢ Subscribers who have registered without key will be notified for all updates
TCP/IP Stack Project -> Notification Chains -> Writing NFC files
tcpip_stack/notif.c
tcpip_stack/notif.h
notif_chain_elem_t
typedef struct notif_chain_ {
char key[MAX_NOTIF_KEY_SIZE];
size_t key_size; typedef void (*nfc_app_cb)(void *, size_t);
bool_t is_key_set;
nfc_app_cb app_cb;
glthread_t glue;
} notif_chain_elem_t;
TCP/IP Stack Project -> Notification Chains -> Writing NFC files
tcpip_stack/notif.c
tcpip_stack/notif.h Subscription Request
void
➢ NFC is a linked list of callbacks ( function pointers) nfc_register_notif_chain (notif_chain_t *nfc,
notif_chain_elem_t *nfce);
char key[MAX_NOTIF_KEY_SIZE];
size_t key_size; typedef void (*nfc_app_cb)(void *, size_t);
bool_t is_key_set;
nfc_app_cb app_cb;
glthread_t glue;
} notif_chain_elem_t;
TCP/IP Stack Project -> Notification Chains -> Interface Events Relay
➢ Now that we have implemented a generic NFC infra, Now we will implement how any change in interface config done by
by the admin can be notified to applications (spf algo) using NFC
➢ Once you understand this pattern of communication, We shall implement several other notification chains in our project to
implement different features
Eg : how application can tell TCP/IP Stack dynamically that in which protocol packets it is interested in
➢ We will write two new files which would represent notification Chains specific to our TCP/IP Stack. These two files would be
wrapper over generic notif.c/notif.h
tcpip_notify.h/.c
To illustrate, let me first implement NFC concept for
notify.h/.c
Interface config change notifications
void
nfc_intf_invoke_notification_to_sbscribers( ➢ To be invoked by NFC to notify subscriber
about change in interface config
interface_t *intf, ➢ Based on change_flags value, subscriber can find
intf_nw_props_t *old_intf_nw_props, out what is changed
uint32_t change_flags); ➢ This routine packs all data into a structure
intf_notif_data_t to be passed as argument to su
Callback fn
➢ Notif need to be generated whenever there is config change on an interface by the user
➢ Publisher must pack all interested data into a single container ( intf_notif_data_t ) to be notified to subscriber
TCP/IP Stack Project -> Notification Chains -> Interface Events Relay
• Appln must de-wrap the structure intf_notif_data_t and find the data of interest in its callback fn
Relevance
Plan
➢ This timer library is based on POSIX threads, so specific to Unix family Operating systems only
➢ We shall first go through the steps for library integration, and then we walk over the timer APIs and how to use them
➢ Timers are used to implement various Networking based problem statements and their solutions
➢ Place in directory :
➢ tcpip_stack/WheelTimer
➢ Update Makefile
➢ Properties :
➢ Currently ARP table entry is static – meaning once installed it shall be there for forever in ARP Table
➢ ARP Table entry my go obsolete as topology changes, and therefore, ARP table entries which are useless should
be deleted from ARP table automatically
➢ If ARP Table entry is not used for traffic forwarding for 30 sec, delete it
➢ If ARP table entry is used for traffic forwarding, refresh its expiration timer back to 30 sec again
➢ Enhance show node <node-name> arp to show expiration time arp entry as an additional field
TCP/IP Stack Project -> Using Timers -> Get Familiar
➢ Solution Steps :
➢ Each Node in the topology, must have its own Wheel-Timer instance running
➢ A Node will schedule all its events using its own Wheel-Timer instance
➢ Now that each ARP table entry is associated with the timer, we need to add below member :
struct arp_entry_{
...
...
wheel_timer_elem_t *exp_timer_wt_elem; /* This represents that this ARP entry is being tracked by Timer now */
};
TCP/IP Stack Project -> Dynamic ARP Tables
wheel_timer_elem_t *
arp_entry_create_expiration_timer( • Should be called when ARP entry is installed in routing table for the first time
node_t *node,
1 arp_entry_t *arp_entry,
uint16_t exp_time);
void
arp_entry_delete_expiration_timer( • Should be called when ARP entry is deleted from ARP Table
2 arp_entry_t *arp_entry);
void
arp_entry_refresh_expiration_timer( • Should be called whenever ARP entry is referenced for traffic forwarding Or
3 arp_entry_t *arp_entry); • Whenever the ARP entry status changed from Sane to Resolved
uint16_t
• Should be used while displaying the arp entry and showing how
arp_entry_get_exp_time_left(arp_entry_t *arp_entry);
4 many seconds remaining for it to expire
Developing
TCP/IP Stack
• How to Implement a new Network Application
Part C
in Application Layer
• Dynamic Protocol Registration
➢ We shall be going to implement a mechanism using which an application can express interest in the packets it is interested
in receiving from underlying TCP/IP stack
➢ Tell our TCP/IP Stack that in which packets (ip_hdr->protocol for L3 pkts & ethernet_hdr->type for
L2 pkts) the application is interested in
➢ Our TCP/IP Stack should handover the pkt to the application based on protocol ( &type) fields
in IP Hdr ( & ethernet hdr)
➢ I will show the implementation for ip_hdr->protocol field, you need to complete it for ethernet_hdr->type field as a
part of assignment
➢ You should be able to realize that it implementation should make use of Notification Chains as it is another typical
case of publisher (Layer3/Layer2) and Subscribers (Applications)
➢ Let us say, we have some dummy appln - ddcp (Distributed Data Collection) running in application layer
➢ DDCP_MSG_TYPE_FLOOD_QUERY
➢ This is L2 packet, meaning the pkt is encapsulated within ethernet hdr
➢ DDCP_MSG_TYPE_UCAST_REPLY
➢ This is L3 pkt , meaning the pkt is encapsulated within IP hdr
TCP/IP Stack Project -> Dynamic Protocol Registration
➢ Let us say, we have some dummy appln - ddcp (Distributed Data Collection) running in application layer
➢ DDCP_MSG_TYPE_FLOOD_QUERY
➢ This is L2 packet, meaning the pkt is encapsulated within ethernet hdr
➢ DDCP_MSG_TYPE_UCAST_REPLY
➢ This is L3 pkt , meaning the pkt is encapsulated within IP hdr
➢ Protocol : DDCP_MSG_TYPE_UCAST_REPLY
➢ Src Addr : Lo address of sender
➢ Recv Addr : lo addr of Receiver
Learn Integrate Timer Library in 30 Minutes
Using Timers
➢ To quickly take a look how we can integrate a ready-made timer library with our
application and start using timers straightaway on linux systems
Src Code
• Suppose at t = 0 , you start a timer of 10 sec to send out a packet to remote machine
• At t = 0 , timer is started
wt = init_wheel_timer( )
start_wheel_timer(wt);
0 1
9 2
wt_elem = register_app_event(wt, . . .)
A handle which 3
application has 8
to cache to
perform future de_register_app_event (wt, 4
7
operations on wt_elem); 6 5
this event wt_elem = NULL;
Using Timers
Application Callback
➢ The Timer library does the application’s work by invoking the Application fn
➢ Application should write the fn of this prototype to be register with the timer
void
/* Creating a new timer */ 1 de_register_app_event (wheel_timer_t *wt,
wheel_timer_elem_t *wt_elem);
wheel_timer_t*
init_wheel_timer(int wheel_size, int clock_tic_interval);
/* Reschedule event again */
/* Starting the new timer */
2 void
void 5
wt_elem_reschedule (wheel_timer_t *wt,
start_wheel_timer(wheel_timer_t *wt);
wheel_timer_elem_t *wt_elem,
int new_time_interval);
/*Scheduling event with the timer */
/* Get Remaining time left for the event to fire */
3
wheel_timer_elem_t * 6 int
register_app_event(wheel_timer_t *wt,
wt_get_remaining_time(wheel_timer_t *wt,
app_call_back call_back,
wheel_timer_elem_t *wt_elem);
void *arg,
int arg_size,
/* Stop the timer */
int time_interval,
char is_recursive);
7 void
cancel_wheel_timer (wheel_timer_t *wt);
Using Timers
Conclusion
➢ Quickly Integrate the timer library with your projects and start using !
➢ Assignment
➢ Src Code :
[Link]
Using Timers
Solution Steps
2. Add a wheel_timer_elem_t member to the rt entry. This member keeps track of the exp timer of the entry
3. Add the time of installing the rt entry into routing Table, schedule the expiration of the rt entry with the Wheel timer
4. Write a new timer callback function. This fn shall be invoked by WheelTimer on timer expiry. This fn should delete the
rt entry after un-scheduling the rt entry with the WheelTimer
Developing
Application
TCP/IP Stack
Transport Layer
Part B
Network Layer
1. Interface Management & statistics
Data link layer
2. Dynamic L3 Route Calculation
No More Manual installation of L3 routes
➢ Notification Chains is an architectural concept used to notify multiple subscribers interested in the particular event
➢ A party which generates an Event is called Publisher, and parties which are interested in being notified of the event
are called subscribers
➢ Once the Event is generated/produced by the Publisher, the Event is pushed to Subscriber(s)
➢ Subscriber can register and de-register for the event at their will
S1
Comm Subs Subs Subs
Info,
E1,E2
S1 S2 S3
Notification Channel :
• Network Sockets (Different Machines)
Publisher
Event E1
• IPCs (Same Machine, Different Processes)
• Callbacks (Same process)
S1 S2 S3
Comm Comm Comm
Info, Info, Info
E1,E2 E1 E2
Routing Table
Mgr
(Publisher,
Thread T0)
➢ Expected LOCs
➢ 1500 – 2000 ( if you implement Fully )
➢ Level of Difficulty : Medium
➢ It’s a concept – So you are free to implement in your fav Programming language, But I will use C for Demo on Linux
➢ NF is used all over the industry (Publisher Subs Model is very common Design pattern of communication)
➢ Create your github account if not already, Do all your coding on github
➢ Along the way you will learn more new programming concepts
➢ TLVs, Timers, KeepAlive msgs
Notification Chains -> Project Components
Subscriber Use:
Register/Unregister for Events APIs
Communication
Common: Routing Table Channel Thread
Data Serialization/Deserialization Mgr ST2
(Publisher,
Thread T0)
Process
The End product of this Course is a NF Chain Library !
SP3
Notification Chains -> Project Code Access
➢ [Link]
Let’s Start … ! ☺
Notification Chains -> Development Phases
Phase 1 : Writing a Sample Publisher Code which is in-charge of sample data source
➢ In our Project, We will create a Publisher – Routing Table Manager who is in-charge of Routing table, a
Data source
Routing Table
Mgr
(Publisher) Dest Mask OIF Gw
➢ Publisher must notify the update of its data source to all subscribers who have subscribed for the update
char gw_ip[16];
char oif[32];
struct rt_entry_ *prev;
struct rt_entry_ *next;
} rt_entry_t;
rt_entry_t *head;
} rt_table_t;
Notification Chains -> Realistic Example
Application
Transport Layer
Network Layer
I2
I1
Data link layer
Physical Layer
Notification Chains -> Realistic Example
➢ In the prev section, we noticed that every time the user changes the physical structure of the topology, user need to
manually trigger spf algo using “run spf all” to update the Routing tables
➢ Our Goal is :
➢ Whenever user does anything which changes the physical topology and require update of routes, then SPF algorithm
must trigger automatically
➢ Events :
➢ Intf up/down SPF ALGO
compute_spf_all_routers( )
➢ Intf IP Address Change
➢ Link metric change Transport Layer
➢ Etc ..
➢ Todo :
➢ How SPF algorithm (any application) Express its interest with NCM in specifically interface up/down events ?
➢ SPF algo may have no interest if user changes the MTU or bandwidth of the interface
➢ How Application can unregister or register for more new events dynamically with NCM ?
SPF ALGO
compute_spf_all_routers( )
Plan :
Transport Layer
1. First we will implement NCM as a mini-lib
Network Layer
2. Test it with dummy publisher/subscriber I2
I1
Notification Data link layer
3. Will integrate this library with TCP/IP stack lib Chains
Module
Physical Layer
TCP/IP Stack Project -> Notification Chains
Notification Chains -> Design and Implementation