Hi, Welcome to my personal wiki. This is meant to be a sink for all the things that I want to keep notes of. This was heavily inspired by the motto of Document Everything by @yoshuawuyts, from his knowledge repository. And thus, might be apparent from the similar title

This book is rendered using mdbook, which is a utility to create books from markdown files, and is heavily used in the rust ecosystem.

Programming Languages

Well, what did you expect? I am a Computer Science and Engineering student. Having said that, here are a few cool resources I found:


Homepage | Book

Rust has a unique ownership model that allows it to guranee memory safety and run without a garbage collector.
From all the programming languages I've come across, rust defenitely has its unique feel to it and requires a different way of thinking.
It has also made me explore design patterns other than OOP (which is taught extensively in schools and colleges)

Highly recommend it if you are interested in high performance or low level languages. Also check it out if you are into high level programming because rust can be quite friendly once you get used to it.


Cool stuff to know about

  • Rust journey to async/await: A cool talk by Steve Klabnik, where he nicely presented the problems faced and their solutions to designing rust's async/await.

Short notes


as_ref() has the signature &Option<T> -> Option<&T>

it turns a reference to an Option into an Option that holds a reference

if we siply try to do opt.unwrap(); with a reference to an option, it will complain that it cannot mov out of borrowed content.

We only have a reference to the Option. unwrapping tries to move the value inside to option out of it. which is not possible with shared references.

Error handling in libraries and binaries

When writing a library, Its common to implement the From<MyCustomErr> trait for the standard library Error type. This allows us to use std::Result along with a custom error type that implements std::error::Error. This enables the users of our library to use our error type, the same way they use the standard Error type.
But writing all the implementations can get boring and often quite repetitive. thiserror is a crate that provides a convinient macro to derive the std::error::Error trait for our custom error type.

When writin a binary, using anyhow gives us some nice convinience traits that is implemented for return types like the context() method: which allows us to add custom error messages when our application returns an error. It also provides an Error type that, when used in the main function, automatically formats the errors nicely to stdout


A list of useful rust packages

  • - Parallelism library for iterable tasks
  • - Faster HashMap and HashSet, drop-in replacement
  • - Convinient macro to derive Error for custom error types


Macros are basically code that generates other code. There are mainly 2 kinds of macros in rust:

  • Declarative macros
  • Procedural macros/Proc Macros

Jonhoo did a nice beginner friendly video on declarative macros on his channel here

Interesting macro patterns


fn main() {
macro_rules! my_macro {
    ($($expr:tt)*) => {
        $crate::MyStruct::myfunc(async move { $($expr)* }).await



Reference Video | Rust doc - cell (module), Cell (struct)

  • Allows mutable sharing
  • No one has a reference to the thing inside a cell. so anyone can modify the cell itself
  • Does not implement Sync
  • can get the value only if:
    1. you have a mutable reference to it (at which point you dont really need a cell)
    2. the type inside implements Copy
  • therefore a cell is usually used for small Copy types
  • useful for when you want multiple things referencing the same thing in a single threaded system
  • Technically all the magic of a Cell is done int the UnsafeCell implementation The compiler has extra info about UnsafeCell and considers it differently. This allows for such behaviour.
  • UnsafeCell implements !Sync and a bunch of other features
  • UnsafeCell also allows us to get an exclusive, mutable reference from a shared reference. This is allowed because the compiler trusts the guy :)


Reference Video | Rust Docs

  • Unlike other types where the borrow checking is done at compile time, RefCell allows us to check whether anyone else is mutating at run time

  • In essence, it allows safe dynamic borrowing

  • Useful in cases where data is not known at compile time: traversal of graphs and trees

  • Refcell is also implemented using UnsafeCell

  • The structure has a way to keep track of how a value is borrowed

  • From the video, a rough implementation of the structure would look like this:

    fn main() {
      // uses this to keep track of how its borrowed
      enum RefState {
          Unshared, // noone has a reference
          Shared(usize), // there are n shared references
          Exclusive, // someone has an exclusive reference
      struct RefCell<T> {
          value: UnsafeCell<T>,
          state: RefState,
  • The basic api should be something like:

    • borrow_mut() -> Option<&mut T> returns None if it has already been borrowed (exclusive/shared)
    • borrow() -> Option<&T> returns None if there has already been an exclusive borrow

    ( there signatures are for understanding. the actual types will differ )

  • But now, we see that its not possble to implement this api directly with a simple RefState because we would have to mutate the state with a shared reference.

  • Here, wrapping the state in a Cell would solve the problem. Because Cell allows us to mutate using a shared reference. Thus the structure becomes:

    fn main() {
        struct RefCell<T> {
          value: UnsafeCell<T>,
          state: Cell<RefState>,
  • This means that RefState would have to implement the Copy trait too

  • Also, similar to Cell, RefCell is not thread safe

  • In practice, if we are implementing RefCell ourselves, we would return custom types, say Ref and RefMut for the borrow and borrow_mut methods. Now, we can have our own impls for the Drop, Deref and DerefMut traits on these new types to keep our state updated. This allows us to gurantee safety for our implementation

Do check the video referenced above for the implementations and more explanation.


Reference Video | Rust docs rc module , Rc struct

  • Rc: sigle threaded reference counting pointers

  • not Sync, not Send. ie: not thread-safe

  • Rc keeps count of the references. when the last reference is dropped, the value inside is also dropped

  • cannot get a mutable reference to the inside unless we use a Cell or RefCell inside Rc

  • so Rc doesnt provide mutability, only provides a way to have multiple references to the same thing

  • its a pointer to some type T, stored on the heap (cant be in a stack because if we have multiple references, whoose stack will have it?)

  • Useful when somethin need to be in multiple places. but who should have the ownership is not really clear. (eg: a config blob in a program)

  • The implementation, conceptually lokks something like:

    fn main() {
    // we create this inner value because the Rc itself should not hold the
    // refcount if it did, each reference to Rc would have its own count
    struct RcInner<T> {
        value: T,
        // here we wrap the usize in a cell because we need to
        // increment/decrement it withou having an exclusive reference
        // this is similar to how RefCell is made
        refcount: Cell<usize>,
    // this is a pointer to a location on the heap. we use the RcInner type
    // here the initial thought woulbe be to use a Box to hold the value but
    // Cloning a box will also clone the thing inside it which we dont want
    struct Rc<T> {
        // note that *const is a raw pointer
        // *mut and *const dont have the gurantees that & and &mut have; that
        // & -> noone has exclusive ref. &mut -> noone has shared reference
        // but that non-gurantee allows us to create what Rc provides ( multiple
        // things can have reference to the same thing )
        // but when using raw pointers, you can only dereference it using
        // an unsafe block and there is nothing much that you can do with it 
        // besides that
        // [CHANGED] inner: *const RcInner<T>, : use NonNull
        inner: NonNull<RcInner<T>>,
        // This marker relates to the dropcheck issue (see point below)
        // This is needed for the completeness of an Rc implementation
        // but dropcheck is a bit complicated and I need more time :)
        // so I have not included it in this code snippet
        // _marker: PhantomData<RcInner<T>>
        // *const and *mut differs in that fot *mut, you _might_ be able to
        // get an exclusive reference and mutate it. but for *conts, its not
        // okay to mutate. so in general, its not possible to go from 
        // a *const to an exclusive reference
    impl<T> Rc<T> {
        pub fn new(v: T) -> Self {
            let inner = Box::new(RcInner {
                value: v,
                refcount: 1,
            Rc {
                // notice that here we are not simple dereferencing the Box
                // like inner: &*inner. This is because the Box will get
                // dropped at the end of this scope. but we need the pointer
                // to still be valid. so we cast it into a raw pointer
                // [CHANGED] inner: Box::into_raw(inner), : use NonNull
                // SAFETY: Box gives a heap allocation, not a null pointer
                inner: unsafe{ NonNull::new_unchecked(Box::into_raw(inner)) },
    // note that we don't require the type T to be Clone. because we dont
    // actually Clone, we only want to increase the RefCount
    impl<T> Clone for Rc<T> {
        fn clone(&self) -> Self {
            // [CHANGED] let inner = unsafe { &*self.inner }; : because NonNull
            // CHANGENOTE: NonNull gives us a as_ref method to dereference
            let inner = unsafe { self.inner.as_ref() };
            // inner.refcount += 1; this is essentially we want to do
            let c = inner.refcount.get();
            inner.refcount.set(c + 1);
            Rc { inner: self.inner  }
    // We also need to impl Deref so that methods on inner can be accessed
    // transparently
    impl Deref for Rc<T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            // SAFETY: self.inner is a Box that is only deallocated when the
            // Rc goes away. here we _have_ an Rc, therefore the Box has not
            // been deallocated. so dereferencing here is fine
            // [CHANGED] &unsafe { &*self.inner }.value : because NonNull
            // CHANGENOTE: NonNull gives us a as_ref method to dereference
            &unsafe { self.inner.as_ref() }.value
    impl Drop<T> for Rc<T> {
        fn drop(&mut self) {
            // [CHANGED] let inner = unsafe { &*self.inner }; : because NonNull
            // CHANGENOTE: NonNull gives us a as_ref method to dereference
            let inner = unsafe { self.inner.as_ref() };
            let c = inner.refcount.get();
            if c == 1 {
                // we are dropping inner here because inner lives till the end
                // of this drop function. but when we drop the Box in the
                // following line, this pointer gets invalidated. this is just
                // to make sure that we dont accidently use it again.
                // here we get back a box from the pointer, which gets dropped
                // immediately
                // [CHANGED] let _ = Box::from_raw(self::inner);
                // CHANGENOTE but we cant just do this with a *const pointer.
                // because as mentioned above, *cont can have multiple
                // references. so the compiler doesnt know if its okay to drop.
                // the actual details are a bit subtle. the concept of
                // _Varience_ in rust ties into it(look into it). Therefore we
                // need to use a NonNull to get a *mut from a Box::from_raw()
                // this caused CHANGEs above, wrapping our box in NonNull
                // Now, NonNull gives us a method as_ptr() to get a *mut
                // SAFETY: at this point, we are the _only_ Rc that is left
                // and we are getting dropped. after this, there wont be any
                // Rcs and no references to T
                let _ = unsafe { Box::from_raw(self::inner.as_ptr()) };
            } else {
                // there are other Rcs. so we do not drop the Box
                inner.refcount.set(c - 1);

Limitations of this implementation of Rc

  • Note that there are still issues in this implementations regarding dropcheck Jon did cover it a little in his stream but Its better to look more into it before writing. It would also make this example less complicated. Learch more about dropcheck in rust in thenomicon
  • Note that in the std lib implementation od Rc, it allows the T to be unsized: pub struct Rc<T> where T: ?Sized {}. Rust normally requires all generic arguments to be Sized. This requires some unstable features to implement ourselves and gets a bit complicated. So its is not covered here. Lookup "Coerced unsized trait" for more info on supporting dynamically sized types
  • We dont explicitly mark Rc as not Send and Sync because NonNull is not Send

Sync Primitives

RwLock (Reader Writer Lock)

Reference video | Rust Doc

  • An RwLock is basically a RefCell whose counters are kept using atomics
  • the read (borrow equivalent for RefCell) and write (borrow_mut equivalent of Refcell) always return the ref/refmut instead of an option so that we dont have to manually poll in a loop. They block the current thread till its available if the borrow cannot succeed yet


  • A Mutex can be considered as a simplified version of RwLock where ther is only borrow_mut. So a Mutex doesnt have to keep a state to count the no. of readers becuse its either we have the reference or someone else has it. Mutex also blocks the thread till it gets a value

Arc (Atomic reference counted)

Reference Video timestamp | Rust doc Arc

  • Thread safe reference counting pointer
  • Almost similar to Rc except that it uses thread safe atomic operations to manage the reference count


Borrow module

Ref video timestmap | Rust Doc


Rust Doc

  • A Cow is a Clone on write smart pointer

  • Its and enum which is either Borrowed or Owned

  • So Cow<T> either contains a Borror<T> or owns T

  • a Cow implements Deref. So if it holds a reference, it just passes-through the access. If it owns the value, the reference is returned

  • If we try to modify the value in a Cow and:

    1. if it owns the value, it simply does the modification
    2. if its a borrowed value/shared reference, it can't directly modify it so it clones the value and turns it into the Owned version and gives us a mutable reference
  • Useful in cases where we only sometimes need to modify a value. eg: a string escaping function

    fn main() {
    // Without using cow, the function would look something like this:
    // fn escape<'a>(s: &'a str) -> String
    // but for a string that does not need to be escaped, allocating a String
    // is wasteful. A Cow allows us to Clone only when its necessary
    // so the function becomes something like:
    fn escape<'a>(s: &'a str) -> Cow<'a, str> {
        if already_escaped(s) {
        } else {
            let mut string = s.to_string();
            // modify (escape) string here
  • a real world example is where the from_utf8_lossy function on Strings returns a Cow<str>. It returns a Borrowed if the string is valid utf-8. Otherwise, it converts it into a Vec and replaces all invalid chars and returns that Owned value. This is a great example where Cow lets you not to modify when not needed.


Useful notes on unix / linux commands



$ZDOTDIR : Root directory for user level zsh configuration. Usually set to ~
$ZDOTDIR/.zshenv : For setting env variables. This is always read
$ZDOTDIR/.zprofile : Read on login shells. Useful to startup window managers
$ZDOTDIR/.zshrc : Read on interactive shells. This is always read when starting a shell unless -f added
$ZDOTDIR/.zlogin : read at the end of login process. Useful for starting cli daemons/utilities
$ZDOTDIR/.zlogout : read when login shell exits. Can be used to unset variables

Each of these files can have a system-wide counterpart at /etc/zsh

Some cool tips

IRC - Internet Relay Chat

IRC is a low-bandwidth method of communication. IRC is very similar to text messaging, but designed around communicating with large groups of users instead of one on one. People familiar with discord can consider it to be the predecessr of discord and many other similar messaging applications.

IRC has different networks of servers, to which a client may connect to. The different networks hosts different channels in them. Channel names usually start with a # sign

Each user on irc is identified by a nick or a nickname. A user may have multiple nicknames associated to him, to prevent conflicts on different channels.


Weechat is an irc client that is extremely customisable. And since its termial app, it can be put in a tmux session, even on servers. Irssi is also a good alternative but I liked weechat a bit better

Now, weechat does support mouse mode, and its nice to have enabled. but in some cases you just want to use the keyboard. But keyboard shortcuts are easy to forget if you take a break from using them.

Useful Links



  • pandoc-citeproc: Manage citations
  • pandoc-crossref: Manage references and numbering


Generate template using

pandoc -D latex

Makefile Example


OUTPUT = build

FLAGS = -s \
		-F pandoc-crossref\
		-F pandoc-citeproc\
		--toc \
		--bibliography bib.bib

all: pdf pre

	pandoc -o $(OUTPUT)/output.pdf $(FLAGS) $(FILES) meta/pdf.yaml
	pandoc -o $(OUTPUT)/presentation.pdf -t beamer $(FILES) meta/presentation.yaml

	rm build/*

Metadata files


title: Hello World
author: Edvin basil Samuval


  - one
  - two
  - three
numbersections: yes
lang: en
babel-lang: english
autoEqnLabels: true
- top=30mm
- left=25mm
- right=25mm
- bottom=30mm
abstract: |



theme: Berkeley
colortheme: seahorse


Writing dockerfiles

  • try to use a smaller base image for prod. usually alpine is a a good choice unless you have distro specific features that you need
  • Specify the version tags for the image explicitly. eg nginx:1.4-alipne3.1
  • use a non-root user for most tasks especially the execution process
  • use multi stage builds to reduce the size of the final image. eg:
# ----- Initial stage with build dependencies ------

FROM node:12.10.4-alpine3.2 AS builder

# Specify ENV vars here
# Specify WORKDIR here if needed
# do the required COPY here
# RUN pre-exec scripts here

# ... do build steps here
# specifying a seperate user here is not really necessary for multistage
# containers since they dont really affect the final runtime

# --------------- NEXT STAGE-----------------

FROM alipne:3.2 as runtime

USER 1000 

# Specify all the above (workdir, envs, etc here)

# copy over any non-dependent files/static assets here
COPY static/ static/
# copy files over from seperate stage
COPY --from=builder /app/build/mybin /app/mybin

# expose the required port here

# Specify the final runtime command
CMD [ "/app/mybin" ]


Main Documentation

Kubernetes is a container orchestration engine

Basic terminology

  • node: A single VM or physical machine running kubernetes. There can be master nodes and worker nodes
  • pods: smallest deployable unit in a cluster. can consist of multiple containers
  • replica set: gurantees a number of pods are up at any given time
  • deployments: defines a desired state of pods. uses replication controllers
  • services: rules to expose a deployment. provides virtual network addresses
  • volumes: provides persistency and file sharing between pods
  • namespace: a way to split a cluster into seperate virtual clusters

Useful commands

  • get x -o wide [ get more info , eg for pods show its ip]
  • create x -o yaml --dry-run > file.yml , edit and apply back
  • helm inspect values stable/nnextcloud > values.yml gets the values file
  • helm install my_name -f values.yml to specify the values file
  • service: type NodePort to use in ingress controller
  • persistentvolumeclaims to create claims, which can be fullfilled by the provider
  • port-forward <resource> locport:remoteport
  • kubectl edit <resource> : easy editing deployments
  • kubectl exec -it bash : interactive terminal
  • kubectl explain <resource> [ --recursive ] : short documentation on resource
  • kubectl get resourcequota : get limits for each resource

Kubernetes Resources



Learning computer networks. Notes on labbing, and other resources based mostly on cisco guides.

Cisco IOS notes

Cisco IOS on VIRL2/CML

Commands for router (or switch)

  • ? displays all the commands available
  • enable or en takes us into privilleged mode
    • enable ? and tabbing would show other options for the enable command
  • configure terminal or conf t to change the configuration. (global config mode)
  • host R1 to set the hostname to R1
  • interface gigabitEthernet 0/0/0 to select the interface
  • no shutdown to enable the interface. By default, router interfaces are shutdown.
  • ip address to configure the ip address
  • end to exit from config mode, back to the privilleged shell
  • try to ping (self) from the enable/privilleged mode
  • copy running-config startup-config saves the config as the startup config
  • wr is an older command to write the config
  • sh run (show run) to see the running config of the router
  • show ip int br (show ip interface brief) for brief overview of all interfaces
  • show arp shows the arp table
  • show users shows the logged in sessions and some connection info
  • from a router, simply typing an ip would try to telnet to that ip
  • show ip route to see the routing tables
    • if this shows "Default gateway is not set", maybe ip routing is just not enabled. go to conf t and use ip routing to enable it
  • if youre not getting any console messages, you can specify to show those in the current session by using terminal monitor in the enable mode
  • if you wanna configure 2 interfaces the same way, it can be done using interface range gig 0/0, gig 1/2. any configuration will apply to both these interfaces. (prolly dont need for now). you could also do something like int range gig 0/1-2


  • cisco routers usually have ip routing enabled. (because its a router. duh). A multi-layer switch can route for others but routing is not enabled by default. this can be turned on using ip routing
  • most configurations can be disabled by prepending a no before the command. so for eg, to disable routing, it would be no ip routing
  • a default gateway can be configured for a switch using ip default-gateway note that this is different from default route for routing decisions. default gateway is for devices that dont route for others. default route is for a frustrated router that has no other choice :). verify that the gateway was set using show ip route
  • for a device that does ip routing, a default gateway is not used. it used the default route for routing packets that it doesnt know of. ip routing is usually done by routers, but an L3 switch can also act as a router by enabling ip routing.
  • Routing can be done using
    • Directly connected interfaces
    • Static routes
    • Dynamic routing using protocols like ospf (see ospf)


  • To create a pool of ips, use ip nat pool MY-POOL netmask The netmask can also be replaced by the prefix-length /24

  • Now we need an access list to match ips for out NAT rules

  • show access list shows the access list useful to setup rules / for setting up NAT/PAT

  • Add rule to access list to specify which addresses to nat by using access-list 1 permit on conf t mode. Note that the last field is the wildcard bit and not a mask. Note that a standard access list can only match on source ip address information. For NAT, this is all we really need. Extended ACLs can match on source/destination ip address and ports, and even match on different layer 4 protocols like tcp/udp.

  • specify the inside and outside interfces using

    • int gig 0/0 -> ip nat out
    • int gig 0/1 -> ip nat inside
  • specify the nat rule using ip nat inside source list 1 interface gig 0/0 overload. g0/0 is the outside interface. overload specifies to use PAT to allow a lot of devices.

  • verify the translations working with do show ip nat translations

  • 1:1 NAT is static

  • N:N (pool to pool) is dynamic

  • N:1 is overload or PAT

NAT lingo

Local and global perspectives

  • Inside Local: Inside ip from larry's perspective: his ip
  • Outside Local: Outside ip from Larry's perspective: google's ip
  • Inside Global: Inside ip from google's perspectie: router's external-facing ip
  • Outside global: Outside ip from google's perspective: google's ip
  • anytime you see local, its larry's perspective. and anytime you see flobal, its google's perspective

Outside nat (this can get ugly ;p)

  • to set the rule, use ip nat outside source static add-route
    • the format is ip nat outside source static <outside global> <outside local> add-route
    • outside local is the ip of google from google's perspective. outside local is ip of outside(google) from larry's perspective (that he believes), which in case of outside NAT will be the ip after the NAT that he will go to to visit google.
    • the add-route is needed here because both the ips (larry's and natted are on the LAN side. so by default, the router does not have to forward it (same network so why forward). But for NAT to occour, there must be routing. add-route adds a 32 bit static route for this, which will look something like [1/0] via


  • Routers need to agree on the following to form neighbourships:
    • Timers: hello messages etc
    • Network/subnet
    • Authentication
    • DR for the segment
    • Area type (for CCNA, usually single area - the backbone). other area types like stub areas exist
  • DRs not needed for p2p (or point to multipoint) links (serial), They go into full adjacency with everybody.
  • DRs only needed
  • In a usual network, the routers have an LSA of type 1. the DR will have an LSA of type 2 which will have its own information, its network and also the connected routers
  • In case its the only router in the network, it will connect itself to "stub" area and not generate LSA type 2s. this can be verified by viewing the database show ip ospf database. When another router shows up, it will start advertising the LSA typ2 2s and switch from stub to a Transit area, where there are multiple ospf speakers
  • Note that if there is only one router and that is the DR, it will not generate a tye 2 LSA (because its unnecessary). So type 2 LSAs are used only when there are 2 or more routers present (running ospf) on that network
  • show ip protocols shaows what all routing protocols are running
  • show ip ospf int brief for info on ospf interfaces (can be used to check full adjacency)
  • in conf t mode, do show ip protocol shows the routing protocols. (lets say we have ospf 1)
  • go to ospf 1 manage using router ospf 1
  • router-id to set the ospf router id. this must be unique across neighbours
  • specify the network using network area 0 to set it to the area. this will make the router check all its inerfaces and if any of the ipv4 addresses start with 10.0.12, it will make it participate in area 0 of ospf. any directly connected networks to those matching interfaces (whatever mask they may be) will also be included in ospf and be advertised and shared with the ospf network. again, this only looks at the ip of the interface, not its subnet mask
  • now the ospf neighbours will have to elect and decide on a DR, BDR and go through the ITELF process to reach full adjacency
  • show ip ospf neighbour will show the neighbourships
  • default-information originate will impose any default static routes to the ospf so every other ospf router will learn the route. This would be needed if a router is not advertising its default route, causing other routers to not have that route information.
  • default-information originate always will always advertise the default route even if it doesnt have a default route.


  • show vlan brief: show available vlans and the associated interfaces
  • show int trunk: to see details for trunking and associated vlans. note that all swithes in the path of a vlan need to be aware of the vlan, even if they are trunking. otherwise, that packet may be dropped
  • create a vlan in conf t mode using vlan 10. If the vlan doesnt already exists, it will be created when you assign an interface. so this step is not compulsory. but its good to be explicit
  • from conf t mode, select the interface you want to assign to the vlan using int g 0/1
  • specify the switchport mode using switchport mode access. For now, we are creating access ports and not trunking
  • specify the vlan to use using switchport access vlan 10


  • from conf t, select the interface to be used for truning using int g 0/1
  • specify the 802.1q standard using switchport trunk encapsulation dot1q to be used for tagging
  • use switchport mode trunk to set the switchport mode to trunking, (and not "access" or "dynamic negotiation") and youre done!
  • verify using show interfaces trunk


  • we first need to specify addresses that are excluded from the dhcp range. this is done using ip dhcp excluded-address The format is first address followed by the last address. So the above command would exclude the addresses from being distributed. This is needed before configuring the pool. individual addresses can also be excluded by not specifying a second ip.

  • Now, create a dhcp pool using ip dhcp pool THE-TEN-POOL. This will create a pool named THE-TEN-POOL and enter the dhcp-config mode. If such a pool already exists, it will just go to edit it.

  • network to specify the range of addressed to hand out. You can also specify the prefix length as well here (quite rare for cisco). so network /24 also works to the hosts.

  • default router to specify the default gateway

  • dns-server to specify the dns server. multiple addresses can also be specifed by daisy chaining. eg: dns-server

  • The lease time can be secified by lease 1 2 3, the format is lease <days> <hours> <minutes>

  • see more options that can be configured using ?. Finally, use exit to exit out of the dhcp-config mode

  • the leases/bindings can be viewed using show ip dhcp binding

  • to make a router use a dhcp address for itself, use ip address dhcp before no shut

  • to configure a router as a relay, select the interface at which the addresses should be distributed using int g0/1. now set the relay using ip helper-address where is the address of the relay on the other network. should be reachable by this router. but the dhcp server may choose to distribute adresses from a different pool than this address


  • Root Switch is selected: Uses oldest (manufactured) switch unless configured otherwise.
  1. Root port is selected based on the better path, using the following criteria with decreasing priority:
    • Lowest Cost. (gigabit has cost 4, FE has cost 19)
    • Lower bridge id. (bridgeid of the from 32582.1111.2222.3333 here 32582 can be configured. the rest is the mac address)
    • Lower port number now, the port with the better path is called the root port
  2. it will turn on 1 designated port per segment. a designated port is a port that is active/alive/forwarding. a segment is any switch link. Now this will also follow the same priority rules as selecting the root port. Note that all ports attackhed to the root switch becomes designated ports.
  3. Any other ports that are left (neither root nor designated ports) are blocked


  • The secret is to create sub interfaces on the interface attached to the trunk port and configure it like any other port
  • Use int gig 0/0.10 to create the .10 sub interface
  • Now configure trunking and vlans. (to be added)


On packet tracer, the switch might be powered off by default. add a power module by dragging it into the switch. (physical tab)

Note that switch interfaces, by default come up. rouer interfaces are shutdown by default

It might take a while for the interfaces to go from orange to green. It is waiting for the spanning trees to check for any loops in the network


Dynamic Routing

Protocols can be static or dynamic

Dynamic can be of different types

  • IGP : Interior Gateway protocol
    • Distance Vector (aka Routing by rumour since routers only get data from neighbours, not directly from other routers)
      • RIP (uses hop count)
      • EIGRP (metric based on lowest bandwidth and route delays)
    • Link State
      • OSPF (cost of each link in the route)
      • IS-IS (cost of each link but costs not calculated automatically. all costs are 10 by default)
  • EGP (Exterior Gateway protocol)
    • Path Vector
      • BGP

Dynamic routing protocols use different metrics to choose the best route

Metrics cannot be compared between protocols

ECMP: Equal Cost Multi Path : When metric is same for two routes, both the routes are added and traffic is load balanced between them

AD: Administrative Distance : Signifies how trustworthy a route is : Lower AD routes will have higher priority. Routes learned through protocols with lower AD will be preferred regardless of the metrics since those metrics cant be compared directly. Note that AD values can be changed manually. Given are some of the ADs:

Directly connected0
Unusable route255