Commit 8e48831a authored by Ondřej Zajíček's avatar Ondřej Zajíček

Vastly improved OSPF reconfiguration.

Now it can handle a change in iface pattern structure.
It can add, remove and reconfigure interfaces, vlinks and areas.
parent 93e868c7
......@@ -22,8 +22,13 @@ static struct ospf_stubnet_config *this_stubnet;
#ifdef OSPFv2
static void
finish_iface_config(struct ospf_iface_patt *ip)
ospf_iface_finish(void)
{
struct ospf_iface_patt *ip = OSPF_PATT;
if (ip->deadint == 0)
ip->deadint = ip->deadc * ip->helloint;
ip->passwords = get_passwords();
if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
......@@ -36,13 +41,57 @@ finish_iface_config(struct ospf_iface_patt *ip)
#ifdef OSPFv3
static void
finish_iface_config(struct ospf_iface_patt *ip)
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)
{
if ((this_area->areaid == 0) && (this_area->stub != 0))
cf_error( "Backbone area cannot be stub");
}
static void
ospf_proto_finish(void)
{
struct ospf_config *cf = OSPF_CFG;
if (EMPTY_LIST(cf->area_list))
cf_error( "No configured areas in OSPF");
int areano = 0;
int backbone = 0;
struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list)
{
areano++;
if (ac->areaid == 0)
backbone = 1;
}
cf->abr = areano > 1;
if (cf->abr && !backbone)
{
struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config));
add_head(&cf->area_list, NODE ac);
init_list(&ac->patt_list);
init_list(&ac->net_list);
init_list(&ac->stubnet_list);
}
if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
cf_error( "No configured areas in OSPF");
}
CF_DECLS
CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG, OSPF_ROUTER_ID)
......@@ -58,12 +107,13 @@ CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT)
CF_GRAMMAR
CF_ADDTO(proto, ospf_proto '}')
CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
ospf_proto_start: proto_start OSPF {
this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config));
this_proto->preference = DEF_PREF_OSPF;
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->rfc1583 = DEFAULT_RFC1583;
OSPF_CFG->tick = DEFAULT_OSPFTICK;
}
......@@ -80,22 +130,21 @@ ospf_proto_item:
| ECMP bool { OSPF_CFG->ecmp = $2 ? DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; if ($4 < 0) cf_error("ECMP limit cannot be negative"); }
| TICK expr { OSPF_CFG->tick = $2; if($2<=0) cf_error("Tick must be greater than zero"); }
| ospf_area '}'
| ospf_area
;
ospf_area_start: AREA idval '{' {
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->stub = 0;
init_list(&this_area->patt_list);
init_list(&this_area->vlink_list);
init_list(&this_area->net_list);
init_list(&this_area->stubnet_list);
}
;
ospf_area: ospf_area_start ospf_area_opts
ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(); }
;
ospf_area_opts:
......@@ -138,7 +187,7 @@ ospf_stubnet_item:
;
ospf_vlink:
ospf_vlink_start '{' ospf_vlink_opts '}' { finish_iface_config(OSPF_PATT); }
ospf_vlink_start '{' ospf_vlink_opts '}' { ospf_iface_finish(); }
| ospf_vlink_start
;
......@@ -152,7 +201,7 @@ ospf_vlink_item:
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| WAIT expr { OSPF_PATT->waitint = $2 ; }
| DEAD expr { OSPF_PATT->dead = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| 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 ; }
......@@ -164,15 +213,16 @@ ospf_vlink_start: VIRTUAL LINK idval
{
if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone");
this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
add_tail(&this_area->vlink_list, NODE this_ipatt);
add_tail(&OSPF_CFG->vlink_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
OSPF_PATT->voa = this_area->areaid;
OSPF_PATT->vid = $3;
OSPF_PATT->helloint = HELLOINT_D;
OSPF_PATT->rxmtint = RXMTINT_D;
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->dead = 0;
OSPF_PATT->deadint = 0;
OSPF_PATT->type = OSPF_IT_VLINK;
init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->autype = OSPF_AUTH_NONE;
......@@ -185,10 +235,8 @@ ospf_iface_item:
| HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
| POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); }
| RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=0) cf_error("Retransmit int must be greater than zero"); }
| 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"); }
| WAIT expr { OSPF_PATT->waitint = $2 ; }
| DEAD expr { OSPF_PATT->dead = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
| 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"); }
| TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
| TYPE BCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
......@@ -198,6 +246,8 @@ 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 ; }
| 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; }
......@@ -281,7 +331,7 @@ ospf_iface_start:
OSPF_PATT->priority = PRIORITY_D;
OSPF_PATT->waitint = WAIT_DMH*HELLOINT_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->dead = 0;
OSPF_PATT->deadint = 0;
OSPF_PATT->type = OSPF_IT_UNDEF;
init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->autype = OSPF_AUTH_NONE;
......@@ -300,7 +350,7 @@ ospf_iface_opt_list:
;
ospf_iface:
ospf_iface_start iface_patt_list ospf_iface_opt_list { finish_iface_config(OSPF_PATT); }
ospf_iface_start iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
;
opttext:
......
......@@ -88,7 +88,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
#else /* OSPFv3 */
tmp = ntohs(ps->deadint);
#endif
if (tmp != ifa->dead)
if (tmp != ifa->deadint)
{
log(L_ERR "%s%I - dead interval mismatch (%d)", beg, faddr, tmp);
return;
......@@ -217,13 +217,13 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
if (ifa->type == OSPF_IT_NBMA)
{
if ((ifa->priority == 0) && (n->priority > 0))
ospf_hello_send(NULL, 0, n);
ospf_hello_send(NULL, OHS_HELLO, n);
}
ospf_neigh_sm(n, INM_HELLOREC);
}
void
ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
ospf_hello_send(timer *timer, int kind, struct ospf_neighbor *dirn)
{
struct ospf_iface *ifa;
struct ospf_hello_packet *pkt;
......@@ -231,7 +231,6 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
struct proto *p;
struct ospf_neighbor *neigh, *n1;
u16 length;
u32 *pp;
int i;
struct nbma_node *nb;
......@@ -276,27 +275,31 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
pkt->options = ifa->oa->options;
#ifdef OSPFv2
pkt->deadint = htonl(ifa->dead);
pkt->deadint = htonl(ifa->deadint);
pkt->dr = htonl(ipa_to_u32(ifa->drip));
pkt->bdr = htonl(ipa_to_u32(ifa->bdrip));
#else /* OSPFv3 */
pkt->deadint = htons(ifa->dead);
pkt->deadint = htons(ifa->deadint);
pkt->dr = htonl(ifa->drid);
pkt->bdr = htonl(ifa->bdrid);
#endif
/* Fill all neighbors */
i = 0;
pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
WALK_LIST(neigh, ifa->neigh_list)
if (kind != OHS_SHUTDOWN)
{
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
u32 *pp = (u32 *) (((u8 *) pkt) + sizeof(struct ospf_hello_packet));
WALK_LIST(neigh, ifa->neigh_list)
{
OSPF_TRACE(D_PACKETS, "Too many neighbors on the interface!");
break;
if ((i+1) * sizeof(u32) + sizeof(struct ospf_hello_packet) > ospf_pkt_bufsize(ifa))
{
log(L_WARN "%s: Too many neighbors on interface %s", p->name, ifa->iface->name);
break;
}
*(pp + i) = htonl(neigh->rid);
i++;
}
*(pp + i) = htonl(neigh->rid);
i++;
}
length = sizeof(struct ospf_hello_packet) + i * sizeof(u32);
......@@ -319,7 +322,7 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn)
int to_all = ifa->state > OSPF_IS_DROTHER;
int me_elig = ifa->priority > 0;
if (poll) /* Poll timer */
if (kind == OHS_POLL) /* Poll timer */
{
WALK_LIST(nb, ifa->nbma_list)
if (!nb->found && (to_all || (me_elig && nb->eligible)))
......
......@@ -12,6 +12,10 @@
void ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa,
struct ospf_neighbor *n, ip_addr faddr);
void ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn);
void ospf_hello_send(timer *timer, 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.
......@@ -16,10 +16,11 @@ 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_remove(struct ospf_iface *ifa);
void ospf_iface_shutdown(struct ospf_iface *ifa);
void ospf_iface_new(struct proto_ospf *po, struct iface *iface, struct ifa *addr, struct ospf_area_config *ac, struct ospf_iface_patt *ip);
void ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa);
void ospf_set_rxbuf_size(struct ospf_iface *ifa, u32 rxbuf);
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);
struct nbma_node *find_nbma_node_in(list *nnl, ip_addr ip);
......@@ -27,5 +28,4 @@ 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_ */
......@@ -23,6 +23,18 @@ flush_lsa(struct top_hash_entry *en, struct proto_ospf *po)
ospf_hash_delete(po->gr, en);
}
void
ospf_flush_area(struct proto_ospf *po, u32 areaid)
{
struct top_hash_entry *en, *nxt;
WALK_SLIST_DELSAFE(en, nxt, po->lsal)
{
if ((LSA_SCOPE(&en->lsa) == LSA_SCOPE_AREA) && (en->domain == areaid))
flush_lsa(en, po);
}
}
/**
* ospf_age
* @po: ospf protocol
......
......@@ -36,5 +36,7 @@ int lsa_validate(struct ospf_lsa_header *lsa, void *body);
struct top_hash_entry * lsa_install_new(struct proto_ospf *po, struct ospf_lsa_header *lsa, u32 domain, void *body);
void ospf_age(struct proto_ospf *po);
void flush_lsa(struct top_hash_entry *en, struct proto_ospf *po);
void ospf_flush_area(struct proto_ospf *po, u32 areaid);
#endif /* _BIRD_OSPF_LSALIB_H_ */
......@@ -349,7 +349,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
case NEIGHBOR_DOWN:
neigh_chstate(n, NEIGHBOR_INIT);
default:
tm_start(n->inactim, n->ifa->dead); /* Restart inactivity timer */
tm_start(n->inactim, n->ifa->deadint); /* Restart inactivity timer */
break;
}
break;
......@@ -548,16 +548,6 @@ find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip)
return NULL;
}
struct ospf_area *
ospf_find_area(struct proto_ospf *po, u32 aid)
{
struct ospf_area *oa;
WALK_LIST(oa, po->area_list)
if (((struct ospf_area *) oa)->areaid == aid)
return oa;
return NULL;
}
/* Neighbor is inactive for a long time. Remove it. */
static void
neighbor_timer_hook(timer * timer)
......
......@@ -15,7 +15,6 @@ void ospf_neigh_sm(struct ospf_neighbor *n, int event);
void bdr_election(struct ospf_iface *ifa);
struct ospf_neighbor *find_neigh(struct ospf_iface *ifa, u32 rid);
struct ospf_neighbor *find_neigh_by_ip(struct ospf_iface *ifa, ip_addr ip);
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
void ospf_neigh_remove(struct ospf_neighbor *n);
void ospf_sh_neigh_info(struct ospf_neighbor *n);
......
This diff is collapsed.
......@@ -81,9 +81,11 @@ struct ospf_config
{
struct proto_config c;
unsigned tick;
int rfc1583;
byte rfc1583;
byte abr;
int ecmp;
list area_list;
list vlink_list;
};
struct nbma_node
......@@ -121,11 +123,10 @@ struct ospf_area_config
{
node n;
u32 areaid;
int stub;
u32 stub;
list patt_list;
list vlink_list;
list net_list;
list stubnet_list;
list net_list; /* List of aggregate networks for that area */
list stubnet_list; /* List of stub networks added to Router LSA */
};
......@@ -167,6 +168,7 @@ struct ospf_iface
struct iface *iface; /* Nest's iface */
struct ifa *addr; /* IP prefix associated with that OSPF iface */
struct ospf_area *oa;
struct ospf_iface_patt *cf;
pool *pool;
sock *sk; /* IP socket (for DD ...) */
list neigh_list; /* List of neigbours */
......@@ -174,7 +176,7 @@ struct ospf_iface
u32 waitint; /* number of sec before changing state from wait */
u32 rxmtint; /* number of seconds between LSA retransmissions */
u32 pollint; /* Poll interval */
u32 dead; /* after "deadint" missing hellos is router dead */
u32 deadint; /* after "deadint" missing hellos is router dead */
u32 vid; /* Id of peer of virtual link */
ip_addr vip; /* IP of peer of virtual link */
struct ospf_iface *vifa; /* OSPF iface which the vlink goes through */
......@@ -252,8 +254,8 @@ struct ospf_iface
#define OSPF_I_OK 0 /* Everything OK */
#define OSPF_I_SK 1 /* Socket open failed */
#define OSPF_I_LL 2 /* Missing link-local address (OSPFv3) */
// u8 sk_spf; /* Socket is a member of SPFRouters group */
u8 sk_dr; /* Socket is a member of DRouters group */
u8 marked; /* Used in OSPF reconfigure */
u16 rxbuf; /* Buffer size */
u8 check_link; /* Whether iface link change is used */
u8 ecmp_weight; /* Weight used for ECMP */
......@@ -715,14 +717,15 @@ struct ospf_area
node n;
u32 areaid;
struct ospf_area_config *ac; /* Related area config, might be NULL */
int origrt; /* Rt lsa origination scheduled? */
struct top_hash_entry *rt; /* My own router LSA */
struct top_hash_entry *pxr_lsa; /* Originated prefix LSA */
list cand; /* List of candidates for RT calc. */
struct fib net_fib; /* Networks to advertise or not */
unsigned stub;
int trcap; /* Transit capability? */
u32 stub; /* 0 or stub area cost */
u32 options; /* Optional features */
byte origrt; /* Rt lsa origination scheduled? */
byte trcap; /* Transit capability? */
byte marked; /* Used in OSPF reconfigure */
struct proto_ospf *po;
struct fib rtr; /* Routing tables for routers */
};
......@@ -753,18 +756,20 @@ struct proto_ospf
struct ospf_iface_patt
{
struct iface_patt i;
u32 type;
u32 stub;
u32 cost;
u32 helloint;
u32 rxmtint;
u32 pollint;
u32 inftransdelay;
u32 priority;
u32 waitint;
u32 deadc;
u32 dead;
u32 type;
u32 deadint;
u32 inftransdelay;
u32 priority;
u32 strictnbma;
u32 stub;
list nbma_list;
u32 voa;
u32 vid;
u16 rxbuf;
u8 check_link;
......@@ -772,9 +777,7 @@ struct ospf_iface_patt
#define OSPF_RXBUF_NORMAL 0
#define OSPF_RXBUF_LARGE 1
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
list nbma_list;
u32 autype; /* Not really used in OSPFv3 */
u32 autype; /* Not really used in OSPFv3 */
#define OSPF_AUTH_NONE 0
#define OSPF_AUTH_SIMPLE 1
#define OSPF_AUTH_CRYPT 2
......@@ -789,24 +792,6 @@ struct ospf_iface_patt
#endif
};
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
static inline int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
{
/*
* We cannot properly support multiple OSPF ifaces on real iface
* with multiple prefixes, therefore we force OSPF ifaces with
* non-primary IP prefixes to be stub.
*/
return ip->stub || !(addr->flags & IA_PRIMARY);
}
#else
static inline int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr UNUSED)
{
return ip->stub;
}
#endif
int ospf_import_control(struct proto *p, rte **new, ea_list **attrs,
struct linpool *pool);
......@@ -816,6 +801,8 @@ void schedule_rt_lsa(struct ospf_area *oa);
void schedule_rtcalc(struct proto_ospf *po);
void schedule_net_lsa(struct ospf_iface *ifa);
struct ospf_area *ospf_find_area(struct proto_ospf *po, u32 aid);
#ifdef OSPFv3
void schedule_link_lsa(struct ospf_iface *ifa);
#else
......
......@@ -1176,6 +1176,7 @@ static void *
originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
{
struct proto_ospf *po = oa->po;
struct ospf_config *cf = (struct ospf_config *) (po->proto.cf);
struct ospf_iface *ifa;
struct ospf_lsa_prefix *lp;
struct ifa *vlink_addr = NULL;
......@@ -1234,7 +1235,7 @@ originate_prefix_rt_lsa_body(struct ospf_area *oa, u16 *length)
/* If there are some configured vlinks, add some global address,
which will be used as a vlink endpoint. */
if (oa->ac && !EMPTY_LIST(oa->ac->vlink_list) && !host_addr && vlink_addr)
if (!EMPTY_LIST(cf->vlink_list) && !host_addr && vlink_addr)
{
lsa_put_prefix(po, vlink_addr->ip, MAX_PREFIX_LENGTH, 0);
i++;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment