Commit 70945cb6 authored by Ondřej Zajíček's avatar Ondřej Zajíček

Temporary integrated OSPF commit.

parent 9eceab33
......@@ -2332,6 +2332,7 @@ protocol ospf <name> {
tx length <num>;
type [broadcast|bcast|pointopoint|ptp|
nonbroadcast|nbma|pointomultipoint|ptmp];
link lsa suppression <switch>;
strict nonbroadcast <switch>;
real broadcast <switch>;
ptp netmask <switch>;
......@@ -2596,9 +2597,16 @@ protocol ospf <name> {
communication, or if the NBMA network is used as an (possibly
unnumbered) PtP link.
<tag>strict nonbroadcast <M>switch</M></tag>
<tag>link lsa suppression <m/switch/</tag>
In OSPFv3, link LSAs are generated for each link, announcing link-local
IPv6 address of the router to its local neighbors. These are useless on
PtP or PtMP networks and this option allows to suppress the link LSA
origination for such interfaces. The option is ignored on other than PtP
or PtMP interfaces. Default value is no.
<tag>strict nonbroadcast <m/switch/</tag>
If set, don't send hello to any undefined neighbor. This switch is
ignored on other than NBMA or PtMP networks. Default value is no.
ignored on other than NBMA or PtMP interfaces. Default value is no.
<tag>real broadcast <m/switch/</tag>
In <cf/type broadcast/ or <cf/type ptp/ network configuration, OSPF
......
......@@ -33,6 +33,12 @@
#define ABS(a) ((a)>=0 ? (a) : -(a))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
#define BIT32_VAL(p) (((u32) 1) << ((p) % 32))
#define BIT32_TEST(b,p) ((b)[(p)/32] & BIT32_VAL(p))
#define BIT32_SET(b,p) ((b)[(p)/32] |= BIT32_VAL(p))
#define BIT32_CLR(b,p) ((b)[(p)/32] &= ~BIT32_VAL(p))
#define BIT32_ZERO(b,l) memset((b), 0, (l)/8)
#ifndef NULL
#define NULL ((void *) 0)
#endif
......
......@@ -68,10 +68,12 @@ typedef struct siterator {
#define SNODE (snode *)
#define SHEAD(list) ((void *)((list).head))
#define STAIL(list) ((void *)((list).tail))
#define WALK_SLIST(n,list) for(n=SHEAD(list);(SNODE (n))->next; \
n=(void *)((SNODE (n))->next))
#define SNODE_NEXT(n) ((void *)((SNODE (n))->next))
#define SNODE_VALID(n) ((SNODE (n))->next)
#define WALK_SLIST(n,list) for(n=SHEAD(list); SNODE_VALID(n); n=SNODE_NEXT(n))
#define WALK_SLIST_DELSAFE(n,nxt,list) \
for(n=SHEAD(list); nxt=(void *)((SNODE (n))->next); n=(void *) nxt)
for(n=SHEAD(list); nxt=SNODE_NEXT(n); n=(void *) nxt)
#define EMPTY_SLIST(list) (!(list).head->next)
void s_add_tail(slist *, snode *);
......
......@@ -21,7 +21,9 @@ static list *this_nets;
static struct area_net_config *this_pref;
static struct ospf_stubnet_config *this_stubnet;
#ifdef OSPFv2
static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
static void
ospf_iface_finish(void)
{
......@@ -38,21 +40,6 @@ ospf_iface_finish(void)
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
log(L_WARN "Password option without authentication option does not make sense");
}
#endif
#ifdef OSPFv3
static void
ospf_iface_finish(void)
{
struct ospf_iface_patt *ip = OSPF_PATT;
if (ip->deadint == 0)
ip->deadint = ip->deadc * ip->helloint;
if ((ip->autype != OSPF_AUTH_NONE) || (get_passwords() != NULL))
cf_error("Authentication not supported in OSPFv3");
}
#endif
static void
ospf_area_finish(void)
......@@ -61,12 +48,12 @@ ospf_area_finish(void)
cf_error("Backbone area cannot be stub/NSSA");
if (this_area->summary && (this_area->type == OPT_E))
cf_error("Only Stub/NSSA areas can use summary propagation");
cf_error("Only stub/NSSA areas can use summary propagation");
if (this_area->default_nssa && ((this_area->type != OPT_N) || ! this_area->summary))
cf_error("Only NSSA areas with summary propagation can use NSSA default route");
if ((this_area->default_cost & LSA_EXT_EBIT) && ! this_area->default_nssa)
if ((this_area->default_cost & LSA_EXT3_EBIT) && ! this_area->default_nssa)
cf_error("Only NSSA default route can use type 2 metric");
}
......@@ -80,15 +67,22 @@ ospf_proto_finish(void)
int areano = 0;
int backbone = 0;
int nssa = 0;
struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list)
{
areano++;
if (ac->areaid == 0)
backbone = 1;
backbone = 1;
if (ac->type == OPT_N)
nssa = 1;
}
cf->abr = areano > 1;
/* Route export or NSSA translation (RFC 3101 3.1) */
cf->asbr = (this_proto->out_filter != FILTER_REJECT) || (nssa && cf->abr);
if (cf->abr && !backbone)
{
struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config));
......@@ -101,26 +95,27 @@ ospf_proto_finish(void)
}
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
cf_error( "Vlinks cannot be used on single area router");
cf_error("Vlinks cannot be used on single area router");
if (cf->asbr && (areano == 1) && (this_area->type == 0))
cf_error("ASBR must be in non-stub area");
}
static inline void
check_defcost(int cost)
ospf_check_defcost(int cost)
{
if ((cost <= 0) || (cost >= LSINFINITY))
cf_error("Default cost must be in range 1-%d", LSINFINITY-1);
}
static inline void
set_instance_id(unsigned id)
ospf_check_auth(void)
{
#ifdef OSPFv3
OSPF_PATT->instance_id = id;
#else
cf_error("Instance ID requires OSPFv3");
#endif
if (ospf_cfg_is_v3())
cf_error("Authentication not supported in OSPFv3");
}
CF_DECLS
CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
......@@ -132,7 +127,7 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
CF_KEYWORDS(SECONDARY, MERGE)
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION)
%type <t> opttext
%type <ld> lsadb_args
......@@ -146,8 +141,8 @@ ospf_proto_start: proto_start OSPF {
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
OSPF_CFG->tick = DEFAULT_OSPFTICK;
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->ospf2 = OSPF_IS_V2;
}
;
......@@ -160,7 +155,7 @@ ospf_proto_item:
proto_item
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
| TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
......@@ -171,9 +166,9 @@ ospf_area_start: AREA idval {
this_area = cfg_allocz(sizeof(struct ospf_area_config));
add_tail(&OSPF_CFG->area_list, NODE this_area);
this_area->areaid = $2;
this_area->default_cost = DEFAULT_STUB_COST;
this_area->default_cost = OSPF_DEFAULT_STUB_COST;
this_area->type = OPT_E;
this_area->transint = DEFAULT_TRANSINT;
this_area->transint = OSPF_DEFAULT_TRANSINT;
init_list(&this_area->patt_list);
init_list(&this_area->net_list);
......@@ -195,9 +190,9 @@ ospf_area_item:
| NSSA { this_area->type = OPT_N; }
| SUMMARY bool { this_area->summary = $2; }
| DEFAULT NSSA bool { this_area->default_nssa = $3; }
| DEFAULT COST expr { this_area->default_cost = $3; check_defcost($3); }
| DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT_EBIT; check_defcost($3); }
| STUB COST expr { this_area->default_cost = $3; check_defcost($3); }
| DEFAULT COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
| DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT3_EBIT; ospf_check_defcost($3); }
| STUB COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
| TRANSLATOR bool { this_area->translator = $2; }
| TRANSLATOR STABILITY expr { this_area->transint = $3; }
| NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}'
......@@ -249,10 +244,10 @@ ospf_vlink_item:
| WAIT expr { OSPF_PATT->waitint = $2 ; }
| DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
| password_list
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
| password_list { ospf_check_auth(); }
;
ospf_vlink_start: VIRTUAL LINK idval
......@@ -292,18 +287,19 @@ ospf_iface_item:
| TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
| TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
| REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (OSPF_VERSION != 2) cf_error("Real broadcast option requires OSPFv2"); }
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (OSPF_VERSION != 2) cf_error("Real netmask option requires OSPFv2"); }
| REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2()) cf_error("Real broadcast option requires OSPFv2"); }
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2()) cf_error("PtP netmask option requires OSPFv2"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| PRIORITY expr { OSPF_PATT->priority = $2 ; if (($2<0) || ($2>255)) cf_error("Priority must be in range 0-255"); }
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
| STUB bool { OSPF_PATT->stub = $2 ; }
| CHECK LINK bool { OSPF_PATT->check_link = $3; }
| ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| LINK LSA SUPPRESSION bool { OSPF_PATT->link_lsa_suppression = $4; if (!ospf_cfg_is_v3()) cf_error("Link LSA suppression option requires OSPFv3"); }
| NEIGHBORS '{' nbma_list '}'
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE ; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE ; }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT ; }
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
| RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
| RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
| RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
......@@ -314,7 +310,7 @@ ospf_iface_item:
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
| SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
| password_list
| password_list { ospf_check_auth(); }
;
pref_list:
......@@ -349,7 +345,7 @@ nbma_eligible:
| ELIGIBLE { $$ = 1; }
;
nbma_item: IPA nbma_eligible ';'
nbma_item: ipa nbma_eligible ';'
{
this_nbma = cfg_allocz(sizeof(struct nbma_node));
add_tail(&OSPF_PATT->nbma_list, NODE this_nbma);
......@@ -384,11 +380,11 @@ ospf_iface_start:
ospf_instance_id:
/* empty */
| INSTANCE expr { set_instance_id($2); }
| INSTANCE expr { OSPF_PATT->instance_id = $2; }
;
ospf_iface_patt_list:
iface_patt_list { if (OSPF_VERSION == 3) iface_patt_check(); } ospf_instance_id
iface_patt_list { if (ospf_cfg_is_v3()) iface_patt_check(); } ospf_instance_id
;
ospf_iface_opts:
......
This diff is collapsed.
/*
* BIRD -- OSPF
*
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_DBDES_H_
#define _BIRD_OSPF_DBDES_H_
void ospf_dbdes_send(struct ospf_neighbor *n, int next);
void ospf_dbdes_receive(struct ospf_packet *ps, struct ospf_iface *ifa,
struct ospf_neighbor *n);
#endif /* _BIRD_OSPF_DBDES_H_ */
This diff is collapsed.
/*
* BIRD -- OSPF
*
* (c) 1999 - 2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_HELLO_H_
#define _BIRD_OSPF_HELLO_H_
void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n, ip_addr faddr);
void ospf_hello_send(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn);
#define OHS_HELLO 0
#define OHS_POLL 1
#define OHS_SHUTDOWN 2
#endif /* _BIRD_OSPF_HELLO_H_ */
This diff is collapsed.
/*
* BIRD -- OSPF
*
* (c) 1999--2005 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_IFACE_H_
#define _BIRD_OSPF_IFACE_H_
void ospf_iface_chstate(struct ospf_iface *ifa, u8 state);
void ospf_iface_sm(struct ospf_iface *ifa, int event);
struct ospf_iface *ospf_iface_find(struct proto_ospf *p, struct iface *what);
void ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface);
void ospf_ifa_notify(struct proto *p, unsigned flags, struct ifa *a);
void ospf_iface_info(struct ospf_iface *ifa);
void ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *ip);
void ospf_iface_new_vlink(struct proto_ospf *po, struct ospf_iface_patt *ip);
void ospf_iface_remove(struct ospf_iface *ifa);
void ospf_iface_shutdown(struct ospf_iface *ifa);
int ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new);
void ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac);
int ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen);
void ospf_open_vlink_sk(struct proto_ospf *po);
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
static inline struct nbma_node *
find_nbma_node(struct ospf_iface *ifa, ip_addr ip)
{ return find_nbma_node_in(&ifa->nbma_list, ip); }
#endif /* _BIRD_OSPF_IFACE_H_ */
/*
* BIRD -- OSPF
*
* (c) 2000-2004 Ondrej Filip <feela@network.cz>
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2009--2014 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
......@@ -9,184 +11,175 @@
#include "ospf.h"
/*
struct ospf_lsack_packet
{
struct ospf_packet ospf_packet;
struct ospf_lsa_header lsh[];
};
struct ospf_packet hdr;
// union ospf_auth auth;
struct ospf_lsa_header lsas[];
};
*/
char *s_queue[] = { "direct", "delayed" };
struct lsa_node
{
node n;
struct ospf_lsa_header lsa;
};
static void ospf_dump_lsack(struct proto *p, struct ospf_lsack_packet *pkt)
static inline void
ospf_lsack_body(struct ospf_proto *p, struct ospf_packet *pkt,
struct ospf_lsa_header **body, uint *count)
{
struct ospf_packet *op = &pkt->ospf_packet;
uint plen = ntohs(pkt->length);
uint hlen = ospf_pkt_hdrlen(p);
ASSERT(op->type == LSACK_P);
ospf_dump_common(p, op);
*body = ((void *) pkt) + hlen;
*count = (plen - hlen) / sizeof(struct ospf_lsa_header);
}
unsigned int i, j;
j = (ntohs(op->length) - sizeof(struct ospf_lsack_packet)) /
sizeof(struct ospf_lsa_header);
static void
ospf_dump_lsack(struct ospf_proto *p, struct ospf_packet *pkt)
{
struct ospf_lsa_header *lsas;
uint i, lsa_count;
for (i = 0; i < j; i++)
ospf_dump_lsahdr(p, pkt->lsh + i);
}
ASSERT(pkt->type == LSACK_P);
ospf_dump_common(p, pkt);
ospf_lsack_body(p, pkt, &lsas, &lsa_count);
for (i = 0; i < lsa_count; i++)
ospf_dump_lsahdr(p, lsas + i);
}
/*
* =====================================
* Note, that h is in network endianity!
* =====================================
*/
void
ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
int queue)
ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int queue)
{
struct lsah_n *no = mb_alloc(n->pool, sizeof(struct lsah_n));
memcpy(&no->lsa, h, sizeof(struct ospf_lsa_header));
/* Note that h_n is in network endianity */
struct lsa_node *no = mb_alloc(n->pool, sizeof(struct lsa_node));
memcpy(&no->lsa, h_n, sizeof(struct ospf_lsa_header));
add_tail(&n->ackl[queue], NODE no);
DBG("Adding (%s) ack for %R, ID: %R, RT: %R, Type: %u\n", s_queue[queue],
n->rid, ntohl(h->id), ntohl(h->rt), h->type);
DBG("Adding %s ack for %R, ID: %R, RT: %R, Type: %u\n",
(queue == ACKL_DIRECT) ? "direct" : "delayed",
n->rid, ntohl(h_n->id), ntohl(h_n->rt), h_n->type);
}
void
ospf_lsack_send(struct ospf_neighbor *n, int queue)
ospf_reset_lsack_queue(struct ospf_neighbor *n)
{
struct ospf_packet *op;
struct ospf_lsack_packet *pk;
u16 len, i = 0;
struct ospf_lsa_header *h;
struct lsah_n *no;
struct ospf_iface *ifa = n->ifa;
struct proto *p = &n->ifa->oa->po->proto;
struct lsa_node *no;
if (EMPTY_LIST(n->ackl[queue]))
return;
WALK_LIST_FIRST(no, n->ackl[ACKL_DELAY])
{
rem_node(NODE no);
mb_free(no);
}
}
pk = ospf_tx_buffer(ifa);
op = &pk->ospf_packet;
static inline void
ospf_send_lsack(struct ospf_neighbor *n, int queue)
{
struct ospf_iface *ifa = n->ifa;
struct ospf_proto *p = ifa->oa->po;
struct ospf_lsa_header *lsas;
struct ospf_packet *pkt;
struct lsa_node *no;
uint i, lsa_max, length;
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
h = pk->lsh;
/* RFC 2328 13.5 */
while (!EMPTY_LIST(n->ackl[queue]))
pkt = ospf_tx_buffer(ifa);
ospf_pkt_fill_hdr(ifa, pkt, LSACK_P);
ospf_lsack_body(p, pkt, &lsas, &lsa_max);
for (i = 0; i < lsa_max && !EMPTY_LIST(n->ackl[queue]); i++)
{
no = (struct lsah_n *) HEAD(n->ackl[queue]);
memcpy(h + i, &no->lsa, sizeof(struct ospf_lsa_header));
DBG("Iter %u ID: %R, RT: %R, Type: %04x\n", i, ntohl((h + i)->id),
ntohl((h + i)->rt), (h + i)->type);
i++;
no = (struct lsa_node *) HEAD(n->ackl[queue]);
memcpy(&lsas[i], &no->lsa, sizeof(struct ospf_lsa_header));
DBG("Iter %u ID: %R, RT: %R, Type: %04x\n",
i, ntohl(lsas[i].id), ntohl(lsas[i].rt), lsas[i].type);
rem_node(NODE no);
mb_free(no);
if ((i * sizeof(struct ospf_lsa_header) +
sizeof(struct ospf_lsack_packet)) > ospf_pkt_maxsize(n->ifa))
{
if (!EMPTY_LIST(n->ackl[queue]))
{
len =
sizeof(struct ospf_lsack_packet) +
i * sizeof(struct ospf_lsa_header);
op->length = htons(len);
DBG("Sending and continuing! Len=%u\n", len);
OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
if (ifa->type == OSPF_IT_BCAST)
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
ospf_send_to_all(ifa);
else if (ifa->cf->real_bcast)
ospf_send_to_bdr(ifa);
else
ospf_send_to(ifa, AllDRouters);
}
else
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
else
ospf_send_to_bdr(ifa);
}
ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P);
i = 0;
}
}
}
len = sizeof(struct ospf_lsack_packet) + i * sizeof(struct ospf_lsa_header);
op->length = htons(len);
DBG("Sending! Len=%u\n", len);
length = ospf_pkt_hdrlen(p) + i * sizeof(struct ospf_lsa_header);
pkt->length = htons(length);
OSPF_PACKET(ospf_dump_lsack, pk, "LSACK packet sent via %s", ifa->ifname);
OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet sent via %s", ifa->ifname);
if (ifa->type == OSPF_IT_BCAST)
{
if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP))
ospf_send_to_all(ifa);
else if (ifa->cf->real_bcast)
ospf_send_to_bdr(ifa);
else
ospf_send_to(ifa, AllDRouters);
ospf_send_to_des(ifa);
}
else
ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE);
}
void
ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
ospf_lsack_send(struct ospf_neighbor *n, int queue)
{
while (!EMPTY_LIST(n->ackl[queue]))
ospf_send_lsack(n, queue);
}
void
ospf_receive_lsack(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_neighbor *n)
{
struct proto *p = &ifa->oa->po->proto;
struct ospf_lsa_header lsa;
struct top_hash_entry *en;
unsigned int i, lsano;
struct ospf_proto *p = ifa->oa->po;
struct ospf_lsa_header lsa, *lsas;
struct top_hash_entry *ret, *en;
uint i, lsa_count;
u32 lsa_type, lsa_domain;
unsigned int size = ntohs(ps_i->length);
if (size < sizeof(struct ospf_lsack_packet))
{
log(L_ERR "Bad OSPF LSACK packet from %I - too short (%u B)", n->ip, size);
return;
}
/* RFC 2328 13.7 */
struct ospf_lsack_packet *ps = (void *) ps_i;
OSPF_PACKET(ospf_dump_lsack, ps, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
/* No need to check length, lsack has only basic header */
ospf_neigh_sm(n, INM_HELLOREC);
OSPF_PACKET(ospf_dump_lsack, pkt, "LSACK packet received from %I via %s", n->ip, ifa->ifname);
if (n->state < NEIGHBOR_EXCHANGE)
return;
lsano = (size - sizeof(struct ospf_lsack_packet)) /
sizeof(struct ospf_lsa_header);
for (i = 0; i < lsano; i++)
ospf_neigh_sm(n, INM_HELLOREC); /* Not in RFC */
ospf_lsack_body(p, pkt, &lsas, &lsa_count);
for (i = 0; i < lsa_count; i++)
{
ntohlsah(ps->lsh + i, &lsa);
u32 dom = ospf_lsa_domain(lsa.type, n->ifa);
if ((en = ospf_hash_find_header(n->lsrth, dom, &lsa)) == NULL)
continue; /* pg 155 */
lsa_ntoh_hdr(&lsas[i], &lsa);
lsa_get_type_domain(&lsa, n->ifa, &lsa_type, &lsa_domain);
if (lsa_comp(&lsa, &en->lsa) != CMP_SAME) /* pg 156 */
ret = ospf_hash_find(n->lsrth, lsa_domain, lsa.id, lsa.rt, lsa_type);
if (!ret)
continue;
if (lsa_comp(&lsa, &ret->lsa) != CMP_SAME)
{
if ((lsa.sn == LSA_MAXSEQNO) && (lsa.age == LSA_MAXAGE))
continue;
OSPF_TRACE(D_PACKETS, "Strange LSACK from %I", n->ip);
OSPF_TRACE(D_PACKETS, "Type: %04x, Id: %R, Rt: %R",
lsa.type, lsa.id, lsa.rt);
lsa_type, lsa.id, lsa.rt);
OSPF_TRACE(D_PACKETS, "I have: Age: %4u, Seq: %08x, Sum: %04x",
en->lsa.age, en->lsa.sn, en->lsa.checksum);
ret->lsa.age, ret->lsa.sn, ret->lsa.checksum);
OSPF_TRACE(D_PACKETS, "He has: Age: %4u, Seq: %08x, Sum: %04x",
lsa.age, lsa.sn, lsa.checksum);
continue;
}
DBG("Deleting LS Id: %R RT: %R Type: %u from LS Retl for neighbor %R\n",
lsa.id, lsa.rt, lsa.type, n->rid);
s_rem_node(SNODE en);
ospf_hash_delete(n->lsrth, en);
en = ospf_hash_find_entry(p->gr, ret);
if (en)
en->ret_count--;
DBG("Deleting LSA (Type: %04x Id: %R Rt: %R) from lsrtl for neighbor %R\n",
lsa_type, lsa.id, lsa.rt, n->rid);
s_rem_node(SNODE ret);
ospf_hash_delete(n->lsrth, ret);
}
}
/*
* BIRD -- OSPF
*
* (c) 2000--2004 Ondrej Filip <feela@network.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_LSACK_H_
#define _BIRD_OSPF_LSACK_H_
struct lsah_n
{
node n;
struct ospf_lsa_header lsa;
};
void ospf_lsack_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n);
void ospf_lsack_send(struct ospf_neighbor *n, int queue);
void ospf_lsack_enqueue(struct ospf_neighbor *n, struct ospf_lsa_header *h,
int queue);
#endif /* _BIRD_OSPF_LSACK_H_ */
This diff is collapsed.
/*
* BIRD -- OSPF
*
* (c) 1999 - 2000 Ondrej Filip <feela@network.cz>
* (c) 1999--2000 Ondrej Filip <feela@network.cz>
* (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2009--2014 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
*/
#ifndef _BIRD_OSPF_LSALIB_H_
#define _BIRD_OSPF_LSALIB_H_
#ifdef CPU_BIG_ENDIAN
static inline void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
static inline void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
static inline void htonlsab(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
static inline void ntohlsab(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
static inline void htonlsab1(void *h, u16 len) { };
static inline void ntohlsab1(void *n, u16 len) { };
static inline void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n) { *n = *h; };
static inline void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h) { *h = *n; };
static inline void lsa_hton_body(void *h, void *n, u16 len) { ASSERT(h != n); memcpy(n, h, len); };
static inline void lsa_ntoh_body(void *n, void *h, u16 len) { ASSERT(n != h); memcpy(h, n, len); };
static inline void lsa_hton_body1(void *h, u16 len) { };
static inline void lsa_ntoh_body1(void *n, u16 len) { };
#else
void htonlsah(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
void ntohlsah(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
void htonlsab(void *h, void *n, u16 len);
void ntohlsab(void *n, void *h, u16 len);
static inline void htonlsab1(void *h, u16 len) { htonlsab(h, h, len); };
static inline void ntohlsab1(void *n, u16 len) { ntohlsab(n, n, len); };
void lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n);
void lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h);
void lsa_hton_body(void *h, void *n, u16 len);
void lsa_ntoh_body(void *n, void *h, u16 len);
static inline void lsa_hton_body1(void *h, u16 len) { lsa_hton_body(h, h, len); };
static inline void lsa_ntoh_body1(void *n, u16 len) { lsa_ntoh_body(n, n, len); };
#endif