Commit fed1bceb authored by Ondřej Zajíček's avatar Ondřej Zajíček
Browse files

Some preliminary IS-IS commit.

parent 8ecbaf9c
......@@ -72,6 +72,14 @@ void config_add_obstacle(struct config *);
void config_del_obstacle(struct config *);
void order_shutdown(void);
static inline void
cf_range(const char *opt, int val, int min, int max)
{
if ((val < min) || (val > max))
cf_error("%s must be in range %d-%d", opt, min, max);
}
#define CONF_DONE 0
#define CONF_PROGRESS 1
#define CONF_QUEUED 2
......
......@@ -26,6 +26,13 @@ CF_HDR
CF_DEFINES
static void
check_u8(unsigned val)
{
if (val > 0xFF)
cf_error("Value %d out of range (0-255)", val);
}
static void
check_u16(unsigned val)
{
......
......@@ -51,7 +51,7 @@ if test "$enable_ipv6" = yes ; then
else
ip=ipv4
SUFFIX=""
all_protocols=bgp,ospf,pipe,rip,static
all_protocols=bgp,ospf,isis,pipe,rip,static
fi
if test "$given_suffix" = yes ; then
......
......@@ -701,6 +701,9 @@ protos_build(void)
#ifdef CONFIG_OSPF
proto_build(&proto_ospf);
#endif
#ifdef CONFIG_ISIS
proto_build(&proto_isis);
#endif
#ifdef CONFIG_PIPE
proto_build(&proto_pipe);
#endif
......
......@@ -75,7 +75,7 @@ void protos_dump_all(void);
extern struct protocol
proto_device, proto_radv, proto_rip, proto_static,
proto_ospf, proto_pipe, proto_bgp;
proto_ospf, proto_isis, proto_pipe, proto_bgp;
/*
* Routing Protocol Instance
......
source=isis.c ifaces.c lsdb.c packets.c
root-rel=../../
dir-name=proto/isis
include ../../Rules
/*
* BIRD -- IS-IS Configuration
*
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
CF_HDR
#include "proto/isis/isis.h"
CF_DEFINES
#define ISIS_CFG ((struct isis_config *) this_proto)
#define ISIS_IFACE ((struct isis_iface_config *) this_ipatt)
static byte area_id_buffer[13];
static byte *area_id_bpos;
CF_DECLS
CF_KEYWORDS(AREA, BCAST, BROADCAST, BUFFER, CSNP, HELLO, HOLD, ID, INTERFACE, ISIS, LEVEL, LIFETIME,
LSP, METRIC, MULT, PASSIVE, POINTOPOINT, PRIORITY, PSNP, PTP, RETRANSMIT, RX, SIZE, SYSTEM,
TX, TYPE)
%type<i> isis_level
CF_GRAMMAR
CF_ADDTO(proto, isis_proto)
isis_proto_start: proto_start ISIS
{
this_proto = proto_config_new(&proto_isis, sizeof(struct isis_config), $1);
init_list(&ISIS_CFG->patt_list);
ISIS_CFG->lsp_lifetime = ISIS_DEFAULT_LSP_LIFETIME;
ISIS_CFG->rx_buffer_size = ISIS_DEFAULT_RX_BUFFER_SIZE;
ISIS_CFG->tx_buffer_size = ISIS_DEFAULT_TX_BUFFER_SIZE;
};
isis_proto_item:
proto_item
| INTERFACE isis_iface
| AREA ID isis_area_id
| SYSTEM ID isis_system_id
| LSP LIFETIME expr { ISIS_CFG->lsp_lifetime = $3; cf_range("LSP lifetime", $3, 300, 65535); }
| RX BUFFER SIZE expr { ISIS_CFG->rx_buffer_size = $4; cf_range("RX buffer size", $4, 256, 65535); }
| TX BUFFER SIZE expr { ISIS_CFG->tx_buffer_size = $4; cf_range("TX buffer size", $4, 256, 65535); }
;
isis_proto_finish:
{
struct isis_config *cf = ISIS_CFG;
if (! cf->areas[0])
cf_error("Missing area ID");
if (cf->rx_buffer_size < cf->tx_buffer_size)
cf_error("RX buffer size must be greater than TX buffer size");
}
isis_proto_opts:
/* empty */
| isis_proto_opts isis_proto_item ';'
;
isis_proto:
isis_proto_start proto_name '{' isis_proto_opts '}';
isis_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct isis_iface_config));
add_tail(&ISIS_CFG->patt_list, NODE this_ipatt);
ISIS_IFACE->levels[ISIS_L1] = ISIS_DEFAULT_LEVEL_1;
ISIS_IFACE->levels[ISIS_L2] = ISIS_DEFAULT_LEVEL_2;
ISIS_IFACE->metric = ISIS_DEFAULT_METRIC;
ISIS_IFACE->priority = ISIS_DEFAULT_PRIORITY;
ISIS_IFACE->hello_int = ISIS_DEFAULT_HELLO_INT;
ISIS_IFACE->hold_int = ISIS_DEFAULT_HOLD_INT;
ISIS_IFACE->hold_mult = ISIS_DEFAULT_HOLD_MULT;
ISIS_IFACE->rxmt_int = ISIS_DEFAULT_RXMT_INT;
ISIS_IFACE->csnp_int = ISIS_DEFAULT_CSNP_INT;
ISIS_IFACE->psnp_int = ISIS_DEFAULT_PSNP_INT;
};
isis_level: expr { $$ = $1 - 1; if (($1 < 1) || ($1 > 2)) cf_error("Level must be 1 or 2"); }
isis_iface_item:
LEVEL isis_level bool { ISIS_IFACE->levels[$2] = $3; }
| LEVEL isis_level PASSIVE { ISIS_IFACE->levels[$2] = ISIS_LEVEL_PASSIVE; }
| PASSIVE bool { ISIS_IFACE->passive = $2; }
| TYPE BROADCAST { ISIS_IFACE->type = ISIS_IT_BCAST; }
| TYPE BCAST { ISIS_IFACE->type = ISIS_IT_BCAST; }
| TYPE POINTOPOINT { ISIS_IFACE->type = ISIS_IT_PTP; }
| TYPE PTP { ISIS_IFACE->type = ISIS_IT_PTP; }
| METRIC expr { ISIS_IFACE->metric = $2; cf_range("Metric", $2, 1, 63); }
| PRIORITY expr { ISIS_IFACE->priority = $2; cf_range("Priority", $2, 1, 127); }
| HELLO expr { ISIS_IFACE->hello_int = $2; cf_range("Hello interval", $2, 1, 65535); }
| HOLD expr { ISIS_IFACE->hold_int = $2; cf_range("Hold interval", $2, 3, 65535); }
| HOLD MULT expr { ISIS_IFACE->hold_mult = $3; cf_range("Hold multiplier", $3, 3, 255); }
| RETRANSMIT expr { ISIS_IFACE->rxmt_int = $2; cf_range("Retransmit interval", $2, 3, 65535); }
| CSNP expr { ISIS_IFACE->csnp_int = $2; cf_range("CSNP interval", $2, 1, 65535); }
| PSNP expr { ISIS_IFACE->psnp_int = $2; cf_range("PSNP interval", $2, 1, 65535); }
;
isis_iface_finish:
{
struct isis_iface_config *ic = ISIS_IFACE;
if (! ic->hold_int)
{
u32 hold_int = ic->hold_mult * (u32) ic->hello_int;
if (hold_int > 65535)
cf_error("Hello interval times Hold multiplier greater than 65535");
ic->hold_int = hold_int;
}
};
isis_iface_opts:
/* empty */
| isis_iface_opts isis_iface_item ';'
;
isis_iface_opt_list:
/* empty */
| '{' isis_iface_opts '}'
;
isis_iface:
isis_iface_start iface_patt_list isis_iface_opt_list isis_iface_finish;
isis_area_id_read:
NUM
{
check_u8($1);
if ($1 == 0)
cf_error("Area ID must not start with 0");
area_id_bpos = area_id_buffer;
*area_id_bpos++ = $1;
}
| isis_area_id_read '-' NUM
{
check_u16($3);
if ((area_id_bpos + 2 - area_id_buffer) > sizeof(area_id_buffer))
cf_error("Area ID too long");
put_u16(area_id_bpos, $3);
area_id_bpos += 2;
}
;
isis_area_id: isis_area_id_read
{
struct isis_area_id *area_id;
int i, blen;
for (i = 0; i < ISIS_AREAS; i++)
if (! ISIS_CFG->areas[i])
goto found;
cf_error("Too many areas");
found:
blen = area_id_bpos - area_id_buffer;
area_id = cfg_allocz(1 + blen);
area_id->length = blen;
memcpy(area_id->body, area_id_buffer, blen);
ISIS_CFG->areas[i] = area_id;
}
isis_system_id: NUM '-' NUM '-' NUM
{
check_u16($1); check_u16($3); check_u16($5);
ISIS_CFG->system_id = (((u64) $1) << 48) | (((u64) $3) << 32) | (((u64) $5) << 16);
}
CF_CODE
CF_END
/*
* BIRD -- IS-IS Interfaces and Neighbors
*
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdlib.h>
#include "isis.h"
static char* ev_name[] = { NULL, "Init", "Change", "RS" };
#ifdef XXX
static void
isis_timer(timer *tm)
{
struct isis_iface *ifa = tm->data;
struct isis_proto *p = ifa->ra;
ISIS_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
isis_send_ra(ifa, 0);
/* Update timer */
ifa->last = now;
unsigned after = ifa->cf->min_ra_int;
after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1);
if (ifa->initial)
ifa->initial--;
if (ifa->initial)
after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL);
tm_start(ifa->timer, after);
}
void
isis_iface_notify(struct isis_iface *ifa, int event)
{
struct isis_proto *p = ifa->p;
if (!ifa->sk)
return;
ISIS_TRACE(D_EVENTS, "Event %s on %s", ev_name[event], ifa->iface->name);
switch (event)
{
case RA_EV_CHANGE:
ifa->plen = 0;
case RA_EV_INIT:
ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
break;
case RA_EV_RS:
break;
}
/* Update timer */
unsigned delta = now - ifa->last;
unsigned after = 0;
if (delta < ifa->cf->min_delay)
after = ifa->cf->min_delay - delta;
tm_start(ifa->timer, after);
}
#endif
/*
isis_dr_election()
{
at least one up, all relevant neighbors and myself
local system becomes or resign -> event lANLevel1/2DesignatedIntermediateSystemChange
becomes ->
set lan-id
originate new and purge old pseudonode LSP
zmena dr -> zmenit lan-id
zmena lan-id -> zmena me LSP
}
*/
static struct isis_iface *
isis_iface_find(struct isis_proto *p, struct iface *what)
{
struct isis_iface *ifa;
WALK_LIST(ifa, p->iface_list)
if (ifa->iface == what)
return ifa;
return NULL;
}
static void
iface_olock_hook(struct object_lock *lock)
{
struct isis_iface *ifa = lock->data;
struct isis_proto *p = ifa->p;
if (! isis_sk_open(ifa))
{
log(L_ERR "%s: Socket open failed on interface %s", p->p.name, ifa->iface->name);
return;
}
// XXX isis_iface_notify(ifa, RA_EV_INIT);
}
static void
l1_hello_timer_hook(timer *timer)
{
struct isis_iface *ifa = (struct isis_iface *) timer->data;
isis_send_lan_hello(ifa, ISIS_L1);
}
static void
l2_hello_timer_hook(timer *timer)
{
struct isis_iface *ifa = (struct isis_iface *) timer->data;
isis_send_lan_hello(ifa, ISIS_L2);
}
static void
ptp_hello_timer_hook(timer *timer)
{
struct isis_iface *ifa = (struct isis_iface *) timer->data;
isis_send_ptp_hello(ifa);
}
static void
csnp_timer_hook(timer *timer)
{
struct isis_iface *ifa = (struct isis_iface *) timer->data;
struct isis_proto *p = ifa->p;
struct isis_lsp *lsp;
int n;
/* FIXME: CSNP rate limiting */
if (XXX)
{
n = 0;
lsp = isis_lsdb_first(p->lsdb[ISIS_L1], lsp, ifa);
while (lsp)
isis_send_csnp(ifa, ISIS_L1, &lsp, n++ == 0);
}
if (XXX)
{
n = 0;
lsp = isis_lsdb_first(p->lsdb[ISIS_L2], lsp, ifa);
while (lsp)
isis_send_csnp(ifa, ISIS_L2, &lsp, n++ == 0);
}
}
static void
psnp_timer_hook(timer *timer)
{
struct isis_iface *ifa = (struct isis_iface *) timer->data;
struct isis_proto *p = ifa->p;
struct isis_lsp *lsp;
if (XXX)
{
lsp = isis_lsdb_first_ssn(p->lsdb[ISIS_L1], lsp, ifa);
while (lsp)
isis_send_psnp(ifa, ISIS_L1, &lsp);
}
if (XXX)
{
lsp = isis_lsdb_first_ssn(p->lsdb[ISIS_L2], lsp, ifa);
while (lsp)
isis_send_psnp(ifa, ISIS_L2, &lsp);
}
}
static void
isis_iface_new(struct isis_proto *p, struct iface *iface, struct isis_iface_config *cf)
{
ISIS_TRACE(D_EVENTS, "Adding interface %s", iface->name);
pool *pool = rp_new(p->p.pool, "ISIS Interface");
struct isis_iface *ifa = mb_allocz(pool, sizeof(struct isis_iface));
add_tail(&p->iface_list, NODE ifa);
ifa->p = p;
ifa->cf = cf;
ifa->iface = iface;
ifa->pool = pool;
init_list(&ifa->neigh_list);
ifa->type = ifa->cf->type;
ifa->levels = ifa->cf->levels;
ifa->priority = ifa->cf->priority;
ifa->hello_int = ifa->cf->hello_int;
ifa->hold_int = ifa->cf->hold_int;
if (ifa->type == ISIS_IT_PASSIVE)
return;
ifa->hello_timer = tm_new_set(pool, hello_timer_hook, ifa, xxx, xxx);
struct object_lock *lock = olock_new(pool);
lock->addr = IPA_NONE;
lock->type = OBJLOCK_IP;
lock->port = ISIS_PROTO;
lock->iface = iface;
lock->data = ifa;
lock->hook = iface_olock_hook;
ifa->lock = lock;
olock_acquire(lock);
}
/*
static inline void
isis_iface_shutdown(struct isis_iface *ifa)
{
if (ifa->sk)
isis_send_ra(ifa, 1);
}
*/
static void
isis_iface_remove(struct isis_iface *ifa)
{
struct isis_proto *p = ifa->p;
ISIS_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
// XXX isis_iface_sm(ifa, ISM_DOWN);
rem_node(NODE ifa);
rfree(ifa->pool);
}
void
isis_if_notify(struct proto *pp, unsigned flags, struct iface *iface)
{
struct isis_proto *p = (struct isis_proto *) pp;
struct isis_config *cf = (struct isis_config *) (pp->cf);
if (iface->flags & IF_IGNORE)
return;
if (flags & IF_CHANGE_UP)
{
struct isis_iface_config *ic = (struct isis_iface_config *)
iface_patt_find(&cf->patt_list, iface, NULL);
if (ic)
isis_iface_new(p, iface, ic);
return;
}
struct isis_iface *ifa = isis_iface_find(p, iface);
if (!ifa)
return;
if (flags & IF_CHANGE_DOWN)
{
isis_iface_remove(ifa);
return;
}
if ((flags & IF_CHANGE_LINK) && (iface->flags & IF_LINK_UP))
isis_iface_notify(ifa, RA_EV_INIT);
}
/*
void
isis_ifa_notify(struct proto *pp, unsigned flags, struct ifa *a)
{
struct isis_proto *p = (struct isis_proto *) pp;
if (a->flags & IA_SECONDARY)
return;
if (a->scope <= SCOPE_LINK)
return;
struct isis_iface *ifa = isis_iface_find(ra, a->iface);
if (ifa)
isis_iface_notify(ifa, RA_EV_CHANGE);
}
*/
static void
hold_timer_hook(timer *timer)
{
struct isis_neighbor *n = (struct isis_neighbor *) timer->data;
struct isis_iface *ifa = n->ifa;
struct isis_proto *p = ifa->p;
// xxx ISIS_TRACE(D_EVENTS, "Hold timer expired for neighbor %I", n->ip);
isis_neighbor_remove(n);
}
struct isis_neighbor *
isis_neighbor_add(struct isis_iface *ifa)
{
struct isis_proto *p = ifa->p;
struct isis_neighbor *n = mb_allocz(ifa->pool, sizeof(struct isis_neighbor));
add_tail(&ifa->neigh_list, NODE n);
n->ifa = ifa;
n->hold_timer = tm_new_set(ifa->pool, hold_timer_hook, n, xxx, xxx);
return (n);
}
void
isis_neighbor_remove(struct isis_neighbor *n)
{
struct isis_iface *ifa = n->ifa;
struct isis_proto *p = ifa->p;
// xxx ISIS_TRACE(D_EVENTS, "Removing neigbor");
rem_node(NODE n);
rfree(n->hold_timer);
}
/*
new:
t neighbourSystemType - podle typu paketu
holdingTimer, priorityOfNeighbour, neighbour-SystemID and areaAddressesOfNeighbour - podle obsahu
mac_addr
state -> init
checknout my sysID in list -> up
*/
/*
* BIRD -- IS-IS
*
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdlib.h>
#include "isis.h"
/**
* DOC: Intermediate System to Intermediate System (IS-IS)
*
* Intermediate System to Intermediate System
* intra-domain routeing information exchange protocol
*
* XXXX
*
* Supported standards:
* - ISO 10589 - main IS-IS standard
* - RFC xxxx -
*/
static struct proto *
isis_init(struct proto_config *c)
{
struct proto *pp = proto_new(c, sizeof(struct isis_proto));