static struct bgp_nexthop_cache * zlookup_read (void) { struct stream *s; uint16_t length; u_char marker; u_char version; uint16_t command __attribute__((unused)); int nbytes __attribute__((unused)); struct in_addr raddr __attribute__((unused)); uint32_t metric; int i; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; s = zlookup->ibuf; stream_reset (s); /* nbytes not being checked */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return NULL; } /* XXX: not checking command */ command = stream_getw (s); /* XXX: not doing anything with raddr */ raddr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); if (nexthop_num) { bnc = bnc_new (); bnc->valid = 1; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = stream_getc (s); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV4: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); nexthop->ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); break; default: /* do nothing */ break; } bnc_nexthop_add (bnc, nexthop); } } else return NULL; return bnc; }
static struct bgp_nexthop_cache * zlookup_read_ipv6 (void) { struct stream *s; uint16_t length; u_char version, marker; struct in6_addr raddr; uint32_t metric; int i; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; s = zlookup->ibuf; stream_reset (s); /* XXX: ignoring nbytes, see also zread_lookup */ stream_read (s, zlookup->sock, 2); length = stream_getw (s); stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return NULL; } /* XXX: ignoring command */ stream_getw (s); /* XXX: not actually doing anything with raddr */ stream_get (&raddr, s, 16); metric = stream_getl (s); nexthop_num = stream_getc (s); if (nexthop_num) { bnc = bnc_new (); bnc->valid = 1; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = stream_getc (s); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV6: stream_get (&nexthop->gate.ipv6, s, 16); break; case ZEBRA_NEXTHOP_IPV6_IFINDEX: case ZEBRA_NEXTHOP_IPV6_IFNAME: stream_get (&nexthop->gate.ipv6, s, 16); nexthop->ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); break; default: /* do nothing */ break; } bnc_nexthop_add (bnc, nexthop); } } else return NULL; return bnc; }
static int decomp_fetch_byte_callback(void *opaque) { stream_mtfdecomp *sm = opaque; return stream_getc(sm->input); }
static int bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) { struct stream *s; int ret; u_int16_t length, command __attribute__((unused)); u_char version, marker; int nbytes __attribute__((unused)); struct in_addr addr __attribute__((unused)); struct in_addr nexthop; u_int32_t metric = 0; u_char nexthop_num; u_char nexthop_type; /* If lookup connection is not available return valid. */ if (zlookup->sock < 0) { if (igpmetric) *igpmetric = 0; return 1; } /* Send query to the lookup connection */ s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP, VRF_DEFAULT); stream_putc (s, p->prefixlen); stream_put_in_addr (s, &p->u.prefix4); stream_putw_at (s, 0, stream_get_endp (s)); /* Write the packet. */ ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return 1; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return 1; } /* Get result. */ stream_reset (s); /* Fetch length. */ /* XXX: not using nbytes */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); /* Fetch whole data. */ nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return 0; } /* XXX: not using command */ command = stream_getw (s); /* XXX: not using addr */ addr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); /* Set IGP metric value. */ if (igpmetric) *igpmetric = metric; /* If there is nexthop then this is active route. */ if (nexthop_num) { nexthop.s_addr = 0; nexthop_type = stream_getc (s); switch (nexthop_type) { case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); /* ifindex */ (void)stream_getl (s); break; default: /* do nothing */ break; } *igpnexthop = nexthop; return 1; } else return 0; }
static int redist_read_ipv4_route(int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; int min_len = 4; if (length < min_len) { zlog_warn("%s %s: short buffer: length=%d min=%d", __FILE__, __PRETTY_FUNCTION__, length, min_len); return -1; } s = zclient->ibuf; ifindex = 0; nexthop.s_addr = 0; /* Type, flags, message. */ api.type = stream_getc(s); api.flags = stream_getc(s); api.message = stream_getc(s); /* IPv4 prefix length. */ memset(&p, 0, sizeof(struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc(s); min_len += PSIZE(p.prefixlen) + CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s", __FILE__, __PRETTY_FUNCTION__, length, min_len, CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); } if (length < min_len) { zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s", __FILE__, __PRETTY_FUNCTION__, length, min_len, CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); return -1; } /* IPv4 prefix. */ stream_get(&p.prefix, s, PSIZE(p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc(s); nexthop.s_addr = stream_get_ipv4(s); } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc(s); ifindex = stream_getl(s); } api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? stream_getc(s) : 0; api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? stream_getl(s) : 0; switch (command) { case ZEBRA_IPV4_ROUTE_ADD: if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: add %s %s/%d " "nexthop %s ifindex %ld metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), ifindex, CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss", api.metric, CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss", api.distance); } break; case ZEBRA_IPV4_ROUTE_DELETE: if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: delete %s %s/%d " "nexthop %s ifindex %ld metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), ifindex, CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss", api.metric, CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss", api.distance); } break; default: zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command); return -1; } sched_rpf_cache_refresh(); return 0; }
/* Zebra client message read function. */ static int zclient_read (struct thread *thread) { int ret; size_t already; uint16_t length, command; uint8_t marker, version; struct zclient *zclient; /* Get socket to zebra. */ zclient = THREAD_ARG (thread); zclient->t_read = NULL; /* Read zebra header (if we don't have it already). */ if ((already = stream_get_endp(zclient->ibuf)) < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, ZEBRA_HEADER_SIZE-already)) == 0) || (nbyte == -1)) { #ifdef ZCLIENT_DEBUG zlog_debug ("zclient connection closed socket [%d].", zclient->sock); #endif return zclient_failed(zclient); } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already)) { /* Try again later. */ zclient_event (ZCLIENT_READ, zclient); return 0; } already = ZEBRA_HEADER_SIZE; } /* Reset to read from the beginning of the incoming packet. */ stream_set_getp(zclient->ibuf, 0); /* Fetch header values. */ length = stream_getw (zclient->ibuf); marker = stream_getc (zclient->ibuf); version = stream_getc (zclient->ibuf); command = stream_getw (zclient->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zclient->sock, marker, version); return zclient_failed(zclient); } if (length < ZEBRA_HEADER_SIZE) { zlog_err("%s: socket %d message length %u is less than %d ", __func__, zclient->sock, length, ZEBRA_HEADER_SIZE); return zclient_failed(zclient); } /* Length check. */ if (length > STREAM_SIZE(zclient->ibuf)) { struct stream *ns; zlog_warn("%s: message size %u exceeds buffer size %lu, expanding...", __func__, length, (u_long)STREAM_SIZE(zclient->ibuf)); ns = stream_new(length); stream_copy(ns, zclient->ibuf); stream_free (zclient->ibuf); zclient->ibuf = ns; } /* Read rest of zebra packet. */ if (already < length) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, length-already)) == 0) || (nbyte == -1)) { #ifdef ZCLIENT_DEBUG zlog_debug("zclient connection closed socket [%d].", zclient->sock); #endif return zclient_failed(zclient); } if (nbyte != (ssize_t)(length-already)) { /* Try again later. */ zclient_event (ZCLIENT_READ, zclient); return 0; } } length -= ZEBRA_HEADER_SIZE; #ifdef ZCLIENT_DEBUG zlog_debug("zclient 0x%p command 0x%x \n", zclient, command); #endif switch (command) { case ZEBRA_ROUTER_ID_UPDATE: if (zclient->router_id_update) ret = (*zclient->router_id_update) (command, zclient, length); break; case ZEBRA_INTERFACE_ADD: if (zclient->interface_add) ret = (*zclient->interface_add) (command, zclient, length); break; case ZEBRA_INTERFACE_DELETE: if (zclient->interface_delete) ret = (*zclient->interface_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) ret = (*zclient->interface_address_add) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_DELETE: if (zclient->interface_address_delete) ret = (*zclient->interface_address_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_UP: if (zclient->interface_up) ret = (*zclient->interface_up) (command, zclient, length); break; case ZEBRA_INTERFACE_DOWN: if (zclient->interface_down) ret = (*zclient->interface_down) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_ADD: if (zclient->ipv4_route_add) ret = (*zclient->ipv4_route_add) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_DELETE: if (zclient->ipv4_route_delete) ret = (*zclient->ipv4_route_delete) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_ADD: if (zclient->ipv6_route_add) ret = (*zclient->ipv6_route_add) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_DELETE: if (zclient->ipv6_route_delete) ret = (*zclient->ipv6_route_delete) (command, zclient, length); break; default: break; } if (zclient->sock < 0) /* Connection was closed during packet processing. */ return -1; /* Register read thread. */ stream_reset(zclient->ibuf); zclient_event (ZCLIENT_READ, zclient); return 0; }
/* Zebra route add and delete treatment. */ static int zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; struct in6_addr nexthop; struct prefix_ipv6 p; s = zclient->ibuf; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, 16); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); stream_getl (s); /* ifindex, unused */ } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; /* Simply ignore link-local address. */ if (IN6_IS_ADDR_LINKLOCAL (&p.prefix)) return 0; if (command == ZEBRA_IPV6_ROUTE_ADD) { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u", zebra_route_string(api.type), inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric); } bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, api.metric, api.type); } else { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d " "nexthop %s metric %u", zebra_route_string(api.type), inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])), api.metric); } bgp_redistribute_delete ((struct prefix *) &p, api.type); } return 0; }
/* peek into option, stores ASN to *as4 if the AS4 capability was found. * Returns 0 if no as4 found, as4cap value otherwise. */ as_t peek_for_as4_capability (struct peer *peer, u_char length) { struct stream *s = BGP_INPUT (peer); size_t orig_getp = stream_get_getp (s); size_t end = orig_getp + length; as_t as4 = 0; /* The full capability parser will better flag the error.. */ if (STREAM_READABLE(s) < length) return 0; if (BGP_DEBUG (as4, AS4)) zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u," " peeking for as4", peer->host, length); /* the error cases we DONT handle, we ONLY try to read as4 out of * correctly formatted options. */ while (stream_get_getp(s) < end) { u_char opt_type; u_char opt_length; /* Check the length. */ if (stream_get_getp (s) + 2 > end) goto end; /* Fetch option type and length. */ opt_type = stream_getc (s); opt_length = stream_getc (s); /* Option length check. */ if (stream_get_getp (s) + opt_length > end) goto end; if (opt_type == BGP_OPEN_OPT_CAP) { unsigned long capd_start = stream_get_getp (s); unsigned long capd_end = capd_start + opt_length; assert (capd_end <= end); while (stream_get_getp (s) < capd_end) { struct capability_header hdr; if (stream_get_getp (s) + 2 > capd_end) goto end; hdr.code = stream_getc (s); hdr.length = stream_getc (s); if ((stream_get_getp(s) + hdr.length) > capd_end) goto end; if (hdr.code == CAPABILITY_CODE_AS4) { if (BGP_DEBUG (as4, AS4)) zlog_info ("[AS4] found AS4 capability, about to parse"); as4 = bgp_capability_as4 (peer, &hdr); goto end; } stream_forward_getp (s, hdr.length); } } } end: stream_set_getp (s, orig_getp); return as4; }
int main (int argc, char **argv) { int ret; FILE *fp; struct stream *s; time_t now; int type; int subtype; size_t len; int source_as; int dest_as; int ifindex; int family; struct in_addr sip; struct in_addr dip; u_int16_t viewno, seq_num; struct prefix_ipv4 p; s = stream_new (10000); if (argc != 2) { fprintf (stderr, "Usage: %s FILENAME\n", argv[0]); exit (1); } fp = fopen (argv[1], "r"); if (!fp) { perror ("fopen"); exit (1); } while (1) { stream_reset (s); ret = fread (s->data, 12, 1, fp); if (!ret || feof (fp)) { printf ("END OF FILE\n"); break; } if (ferror (fp)) { printf ("ERROR OF FREAD\n"); break; } /* Extract header. */ now = stream_getl (s); type = stream_getw (s); subtype = stream_getw (s); len = stream_getl (s); printf ("TIME: %s", ctime (&now)); /* printf ("TYPE: %d/%d\n", type, subtype); */ if (type == MSG_PROTOCOL_BGP4MP) printf ("TYPE: BGP4MP"); else if (type == MSG_PROTOCOL_BGP4MP_ET) printf ("TYPE: BGP4MP_ET"); else if (type == MSG_TABLE_DUMP) printf ("TYPE: MSG_TABLE_DUMP"); else printf ("TYPE: Unknown %d", type); if (type == MSG_TABLE_DUMP) switch (subtype) { case AFI_IP: printf ("/AFI_IP\n"); break; case AFI_IP6: printf ("/AFI_IP6\n"); break; default: printf ("/UNKNOWN %d", subtype); break; } else { switch (subtype) { case BGP4MP_STATE_CHANGE: printf ("/CHANGE\n"); break; case BGP4MP_MESSAGE: printf ("/MESSAGE\n"); break; case BGP4MP_ENTRY: printf ("/ENTRY\n"); break; case BGP4MP_SNAPSHOT: printf ("/SNAPSHOT\n"); break; default: printf ("/UNKNOWN %d", subtype); break; } } printf ("len: %zd\n", len); ret = fread (s->data + 12, len, 1, fp); if (feof (fp)) { printf ("ENDOF FILE 2\n"); break; } if (ferror (fp)) { printf ("ERROR OF FREAD 2\n"); break; } /* printf ("now read %d\n", len); */ if (type == MSG_TABLE_DUMP) { u_char status; time_t originated; struct in_addr peer; u_int16_t attrlen; viewno = stream_getw (s); seq_num = stream_getw (s); printf ("VIEW: %d\n", viewno); printf ("SEQUENCE: %d\n", seq_num); /* start */ while (s->getp < len - 16) { p.prefix.s_addr = stream_get_ipv4 (s); p.prefixlen = stream_getc (s); printf ("PREFIX: %s/%d\n", inet_ntoa (p.prefix), p.prefixlen); status = stream_getc (s); originated = stream_getl (s); peer.s_addr = stream_get_ipv4 (s); source_as = stream_getw(s); printf ("FROM: %s AS%d\n", inet_ntoa (peer), source_as); printf ("ORIGINATED: %s", ctime (&originated)); attrlen = stream_getw (s); printf ("ATTRLEN: %d\n", attrlen); attr_parse (s, attrlen); printf ("STATUS: 0x%x\n", status); } } else { source_as = stream_getw (s); dest_as = stream_getw (s); printf ("source_as: %d\n", source_as); printf ("dest_as: %d\n", dest_as); ifindex = stream_getw (s); family = stream_getw (s); printf ("ifindex: %d\n", ifindex); printf ("family: %d\n", family); sip.s_addr = stream_get_ipv4 (s); dip.s_addr = stream_get_ipv4 (s); printf ("saddr: %s\n", inet_ntoa (sip)); printf ("daddr: %s\n", inet_ntoa (dip)); printf ("\n"); } } fclose (fp); return 0; }
/* Zebra client message read function. */ int zclient_read (struct thread *thread) { int ret; int nbytes; int sock; zebra_size_t length; zebra_command_t command; #undef zclient struct_zclient *zclient; /* Get socket to zebra. */ sock = THREAD_FD (thread); zclient = THREAD_ARG (thread); zclient->t_read = NULL; /* Clear input buffer. */ stream_reset (zclient->ibuf); /* Read zebra header. */ nbytes = stream_read (zclient->ibuf, sock, ZEBRA_HEADER_SIZE); /* zebra socket is closed. */ if (nbytes == 0) { if (zclient_debug) zlog_debug ("zclient connection closed socket [%d].", sock); zclient->fail++; zclient_stop (zclient); zclient_event (ZCLIENT_CONNECT, zclient); return -1; } /* zebra read error. */ if (nbytes < 0 || nbytes != ZEBRA_HEADER_SIZE) { if (zclient_debug) zlog_debug ("Can't read all packet (length %d).", nbytes); zclient->fail++; zclient_stop (zclient); zclient_event (ZCLIENT_CONNECT, zclient); return -1; } /* Fetch length and command. */ length = stream_getw (zclient->ibuf); command = stream_getc (zclient->ibuf); /* Length check. */ if (length >= zclient->ibuf->size) { stream_free (zclient->ibuf); zclient->ibuf = stream_new (length + 1); } length -= ZEBRA_HEADER_SIZE; /* Read rest of zebra packet. */ nbytes = stream_read (zclient->ibuf, sock, length); if (nbytes != length) { if (zclient_debug) zlog_debug ("zclient connection closed socket [%d].", sock); zclient->fail++; zclient_stop (zclient); zclient_event (ZCLIENT_CONNECT, zclient); return -1; } if (zclient_debug) zlog_debug("zclient 0x%p command 0x%x \n", zclient, command); switch (command) { case ZEBRA_ROUTER_ID_UPDATE: if (zclient->router_id_update) ret = (*zclient->router_id_update) (command, zclient, length); break; case ZEBRA_INTERFACE_ADD: if (zclient->interface_add) ret = (*zclient->interface_add) (command, zclient, length); break; case ZEBRA_INTERFACE_DELETE: if (zclient->interface_delete) ret = (*zclient->interface_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_ADD: if (zclient->interface_address_add) ret = (*zclient->interface_address_add) (command, zclient, length); break; case ZEBRA_INTERFACE_ADDRESS_DELETE: if (zclient->interface_address_delete) ret = (*zclient->interface_address_delete) (command, zclient, length); break; case ZEBRA_INTERFACE_UP: if (zclient->interface_up) ret = (*zclient->interface_up) (command, zclient, length); break; case ZEBRA_INTERFACE_DOWN: if (zclient->interface_down) ret = (*zclient->interface_down) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_ADD: if (zclient->ipv4_route_add) ret = (*zclient->ipv4_route_add) (command, zclient, length); break; case ZEBRA_IPV4_ROUTE_DELETE: if (zclient->ipv4_route_delete) ret = (*zclient->ipv4_route_delete) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_ADD: if (zclient->ipv6_route_add) ret = (*zclient->ipv6_route_add) (command, zclient, length); break; case ZEBRA_IPV6_ROUTE_DELETE: if (zclient->ipv6_route_delete) ret = (*zclient->ipv6_route_delete) (command, zclient, length); break; default: break; } /* Register read thread. */ zclient_event (ZCLIENT_READ, zclient); return 0; }
struct connected * zebra_interface_address_read (int type, struct stream *s) { unsigned int ifindex; struct interface *ifp; struct connected *ifc; struct prefix p, d; int family; int plen; u_char ifc_flags; memset (&p, 0, sizeof(p)); memset (&d, 0, sizeof(d)); /* Get interface index. */ ifindex = stream_getl (s); /* Lookup index. */ ifp = if_lookup_by_index (ifindex); if (ifp == NULL) { zlog_warn ("zebra_interface_address_read(%s): " "Can't find interface by ifindex: %d ", (type == ZEBRA_INTERFACE_ADDRESS_ADD? "ADD" : "DELETE"), ifindex); return NULL; } /* Fetch flag. */ ifc_flags = stream_getc (s); /* Fetch interface address. */ family = p.family = stream_getc (s); plen = prefix_blen (&p); stream_get (&p.u.prefix, s, plen); p.prefixlen = stream_getc (s); /* Fetch destination address. */ stream_get (&d.u.prefix, s, plen); d.family = family; if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { /* N.B. NULL destination pointers are encoded as all zeroes */ ifc = connected_add_by_prefix(ifp, &p,(memconstant(&d.u.prefix,0,plen) ? NULL : &d)); if (ifc != NULL) { ifc->flags = ifc_flags; if (ifc->destination) ifc->destination->prefixlen = ifc->address->prefixlen; else if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER)) { /* carp interfaces on OpenBSD with 0.0.0.0/0 as "peer" */ char buf[BUFSIZ]; prefix2str (ifc->address, buf, sizeof(buf)); zlog_warn("warning: interface %s address %s " "with peer flag set, but no peer address!", ifp->name, buf); UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER); } } } else { assert (type == ZEBRA_INTERFACE_ADDRESS_DELETE); ifc = connected_delete_by_prefix(ifp, &p); } return ifc; }
static int stream_get(stream_t *stream, ph_var_err_t *error) { int c; if (stream->state != STREAM_STATE_OK) { return stream->state; } if (!stream->buffer[stream->buffer_pos]) { uint8_t count; c = stream_getc(stream); if (c == STREAM_STATE_EOF) { return c; } stream->buffer[0] = c; stream->buffer_pos = 0; count = ph_utf8_seq_len(c); if (!count) { goto out; } if (count > 1) { /* multi-byte UTF-8 sequence */ int i; assert(count >= 2); for (i = 1; i < count; i++) { stream->buffer[i] = stream_getc(stream); } if (!utf8_check_full(stream->buffer, count)) { goto out; } stream->buffer[count] = '\0'; } else { stream->buffer[1] = '\0'; } } c = stream->buffer[stream->buffer_pos++]; stream->position++; if (c == '\n') { stream->line++; stream->last_column = stream->column; stream->column = 0; } else if (ph_utf8_seq_len(c) > 0) { /* track the Unicode character column, so increment only if this is the first character of a UTF-8 sequence */ stream->column++; } return c; out: stream->state = STREAM_STATE_ERROR; error_set(error, stream_to_lex(stream), "unable to decode byte 0x%02x", (uint8_t)c); return STREAM_STATE_ERROR; }
int ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex; struct prefix_ipv6 p; struct in6_addr *nexthop; char prefixstr[128], nexthopstr[128]; s = zclient->ibuf; ifindex = 0; nexthop = NULL; memset (&api, 0, sizeof (api)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop = (struct in6_addr *) malloc (api.nexthop_num * sizeof (struct in6_addr)); stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr)); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; /* log */ if (IS_OSPF6_DUMP_ZEBRA) { prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr)); inet_ntop (AF_INET6, &nexthop, nexthopstr, sizeof (nexthopstr)); if (command == ZEBRA_IPV6_ROUTE_ADD) zlog_info ("ZEBRA: Receive add %s route: %s nexthop:%s ifindex:%ld", zebra_route_name [api.type], prefixstr, nexthopstr, ifindex); else zlog_info ("ZEBRA: Receive remove %s route: %s nexthop:%s ifindex:%ld", zebra_route_name [api.type], prefixstr, nexthopstr, ifindex); } if (command == ZEBRA_IPV6_ROUTE_ADD) ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p, api.nexthop_num, nexthop); else ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) free (nexthop); return 0; }
static int bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) { struct stream *s = BGP_INPUT (peer); u_int16_t restart_flag_time; size_t end = stream_get_getp (s) + caphdr->length; SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); restart_flag_time = stream_getw(s); if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV); UNSET_FLAG (restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; if (BGP_DEBUG (normal, NORMAL)) { zlog_debug ("%s OPEN has Graceful Restart capability", peer->host); zlog_debug ("%s Peer has%srestarted. Restart Time : %d", peer->host, CHECK_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV) ? " " : " not ", peer->v_gr_restart); } while (stream_get_getp (s) + 4 <= end) { afi_t afi = stream_getw (s); safi_t safi = stream_getc (s); u_char flag = stream_getc (s); if (!bgp_afi_safi_valid_indices (afi, &safi)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported." " Ignore the Graceful Restart capability", peer->host, afi, safi); } else if (!peer->afc[afi][safi]) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled." " Ignore the Graceful Restart capability", peer->host, afi, safi); } else { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Address family %s is%spreserved", peer->host, afi_safi_print (afi, safi), CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV) ? " " : " not "); SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); if (CHECK_FLAG (flag, RESTART_F_BIT)) SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV); } } return 0; }
/* Handler of zebra service request. */ static int zebra_client_read (struct thread *thread) { int sock; struct zserv *client; size_t already; uint16_t length, command; uint8_t marker, version; /* Get thread data. Reset reading thread because I'm running. */ sock = THREAD_FD (thread); client = THREAD_ARG (thread); client->t_read = NULL; if (client->t_suicide) { zebra_client_close(client); return -1; } /* Read length and command (if we don't have it already). */ if ((already = stream_get_endp(client->ibuf)) < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try (client->ibuf, sock, ZEBRA_HEADER_SIZE-already)) == 0) || (nbyte == -1)) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed socket [%d]", sock); zebra_client_close (client); return -1; } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE-already)) { /* Try again later. */ zebra_event (ZEBRA_READ, sock, client); return 0; } already = ZEBRA_HEADER_SIZE; } /* Reset to read from the beginning of the incoming packet. */ stream_set_getp(client->ibuf, 0); /* Fetch header values */ length = stream_getw (client->ibuf); marker = stream_getc (client->ibuf); version = stream_getc (client->ibuf); command = stream_getw (client->ibuf); if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, sock, marker, version); zebra_client_close (client); return -1; } if (length < ZEBRA_HEADER_SIZE) { zlog_warn("%s: socket %d message length %u is less than header size %d", __func__, sock, length, ZEBRA_HEADER_SIZE); zebra_client_close (client); return -1; } if (length > STREAM_SIZE(client->ibuf)) { zlog_warn("%s: socket %d message length %u exceeds buffer size %lu", __func__, sock, length, (u_long)STREAM_SIZE(client->ibuf)); zebra_client_close (client); return -1; } /* Read rest of data. */ if (already < length) { ssize_t nbyte; if (((nbyte = stream_read_try (client->ibuf, sock, length-already)) == 0) || (nbyte == -1)) { if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("connection closed [%d] when reading zebra data", sock); zebra_client_close (client); return -1; } if (nbyte != (ssize_t)(length-already)) { /* Try again later. */ zebra_event (ZEBRA_READ, sock, client); return 0; } } length -= ZEBRA_HEADER_SIZE; /* Debug packet information. */ if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("zebra message comes from socket [%d]", sock); if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV) zlog_debug ("zebra message received [%s] %d", zserv_command_string (command), length); switch (command) { case ZEBRA_ROUTER_ID_ADD: zread_router_id_add (client, length); break; case ZEBRA_ROUTER_ID_DELETE: zread_router_id_delete (client, length); break; case ZEBRA_INTERFACE_ADD: zread_interface_add (client, length); break; case ZEBRA_INTERFACE_DELETE: zread_interface_delete (client, length); break; case ZEBRA_IPV4_ROUTE_ADD: zread_ipv4_add (client, length); break; case ZEBRA_IPV4_ROUTE_DELETE: zread_ipv4_delete (client, length); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_ROUTE_ADD: zread_ipv6_add (client, length); break; case ZEBRA_IPV6_ROUTE_DELETE: zread_ipv6_delete (client, length); break; #endif /* HAVE_IPV6 */ case ZEBRA_REDISTRIBUTE_ADD: zebra_redistribute_add (command, client, length); break; case ZEBRA_REDISTRIBUTE_DELETE: zebra_redistribute_delete (command, client, length); break; case ZEBRA_REDISTRIBUTE_DEFAULT_ADD: zebra_redistribute_default_add (command, client, length); break; case ZEBRA_REDISTRIBUTE_DEFAULT_DELETE: zebra_redistribute_default_delete (command, client, length); break; case ZEBRA_IPV4_NEXTHOP_LOOKUP: zread_ipv4_nexthop_lookup (client, length); break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: zread_ipv6_nexthop_lookup (client, length); break; #endif /* HAVE_IPV6 */ case ZEBRA_IPV4_IMPORT_LOOKUP: zread_ipv4_import_lookup (client, length); break; case ZEBRA_HELLO: zread_hello (client); break; default: zlog_info ("Zebra received unknown command %d", command); break; } if (client->t_suicide) { /* No need to wait for thread callback, just kill immediately. */ zebra_client_close(client); return -1; } stream_reset (client->ibuf); zebra_event (ZEBRA_READ, sock, client); return 0; }
/** * Parse given capability. * XXX: This is reading into a stream, but not using stream API * * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol * capabilities were encountered. */ static int bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, u_char **error) { int ret; struct stream *s = BGP_INPUT (peer); size_t end = stream_get_getp (s) + length; assert (STREAM_READABLE (s) >= length); while (stream_get_getp (s) < end) { size_t start; u_char *sp = stream_pnt (s); struct capability_header caphdr; /* We need at least capability code and capability length. */ if (stream_get_getp(s) + 2 > end) { zlog_info ("%s Capability length error (< header)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } caphdr.code = stream_getc (s); caphdr.length = stream_getc (s); start = stream_get_getp (s); /* Capability length check sanity check. */ if (start + caphdr.length > end) { zlog_info ("%s Capability length error (< length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s capability (%u), length %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.code, caphdr.length); /* Length sanity check, type-specific, for known capabilities */ switch (caphdr.code) { case CAPABILITY_CODE_MP: case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH_OLD: case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: case CAPABILITY_CODE_RESTART: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info ("%s %s Capability length error: got %u," " expected at least %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length, (unsigned) cap_minsizes[caphdr.code]); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } if (caphdr.length && caphdr.length % cap_modsizes[caphdr.code] != 0) { zlog_info ("%s %s Capability length error: got %u," " expected a multiple of %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length, (unsigned) cap_modsizes[caphdr.code]); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } /* we deliberately ignore unknown codes, see below */ default: break; } switch (caphdr.code) { case CAPABILITY_CODE_MP: { *mp_capability = 1; /* Ignore capability when override-capability is set. */ if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { /* Set negotiated value. */ ret = bgp_capability_mp (peer, &caphdr); /* Unsupported Capability. */ if (ret < 0) { /* Store return data. */ memcpy (*error, sp, caphdr.length + 2); *error += caphdr.length + 2; } } } break; case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH_OLD: { /* BGP refresh capability */ if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD) SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); else SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); } break; case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: if (bgp_capability_orf_entry (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_RESTART: if (bgp_capability_restart (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_DYNAMIC: SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); break; case CAPABILITY_CODE_AS4: /* Already handled as a special-case parsing of the capabilities * at the beginning of OPEN processing. So we care not a jot * for the value really, only error case. */ if (!bgp_capability_as4 (peer, &caphdr)) return -1; break; default: if (caphdr.code > 128) { /* We don't send Notification for unknown vendor specific capabilities. It seems reasonable for now... */ zlog_warn ("%s Vendor specific capability %d", peer->host, caphdr.code); } else { zlog_warn ("%s unrecognized capability code: %d - ignored", peer->host, caphdr.code); memcpy (*error, sp, caphdr.length + 2); *error += caphdr.length + 2; } } if (stream_get_getp(s) != (start + caphdr.length)) { if (stream_get_getp(s) > (start + caphdr.length)) zlog_warn ("%s Cap-parser for %s read past cap-length, %u!", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length); stream_set_getp (s, start + caphdr.length); } } return 0; }
/* * Parse the ZEBRA_IPV4_ROUTE_ADD sent from client. Update rib and * add kernel route. */ static int zread_ipv4_add (struct zserv *client, u_short length) { int i; struct rib *rib; struct prefix_ipv4 p; u_char message; struct in_addr nexthop; u_char nexthop_num; u_char nexthop_type; struct stream *s; unsigned int ifindex; u_char ifname_len; safi_t safi; /* Get input stream. */ s = client->ibuf; /* Allocate new rib. */ rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); /* Type, flags, message. */ rib->type = stream_getc (s); rib->flags = stream_getc (s); message = stream_getc (s); safi = stream_getw (s); rib->uptime = time (NULL); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop parse. */ if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP)) { nexthop_num = stream_getc (s); for (i = 0; i < nexthop_num; i++) { nexthop_type = stream_getc (s); switch (nexthop_type) { case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); nexthop_ifindex_add (rib, ifindex); break; case ZEBRA_NEXTHOP_IFNAME: ifname_len = stream_getc (s); stream_forward_getp (s, ifname_len); break; case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); nexthop_ipv4_add (rib, &nexthop, NULL); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); ifindex = stream_getl (s); nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; case ZEBRA_NEXTHOP_BLACKHOLE: nexthop_blackhole_add (rib); break; } } } /* Distance. */ if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) rib->distance = stream_getc (s); /* Metric. */ if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) rib->metric = stream_getl (s); /* Table */ rib->table=zebrad.rtm_table_default; rib_add_ipv4_multipath (&p, rib, safi); return 0; }
/** * Parse open option. * * @param[out] mp_capability @see bgp_capability_parse() for semantics. */ int bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) { int ret; u_char *error; u_char error_data[BGP_MAX_PACKET_SIZE]; struct stream *s = BGP_INPUT(peer); size_t end = stream_get_getp (s) + length; ret = 0; error = error_data; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u", peer->host, length); while (stream_get_getp(s) < end) { u_char opt_type; u_char opt_length; /* Must have at least an OPEN option header */ if (STREAM_READABLE(s) < 2) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } /* Fetch option type and length. */ opt_type = stream_getc (s); opt_length = stream_getc (s); /* Option length check. */ if (STREAM_READABLE (s) < opt_length) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u", peer->host, opt_type, opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" : opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown", opt_length); switch (opt_type) { case BGP_OPEN_OPT_AUTH: ret = bgp_auth_parse (peer, opt_length); break; case BGP_OPEN_OPT_CAP: ret = bgp_capability_parse (peer, opt_length, mp_capability, &error); break; default: bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_PARAM); ret = -1; break; } /* Parse error. To accumulate all unsupported capability codes, bgp_capability_parse does not return -1 when encounter unsupported capability code. To detect that, please check error and erro_data pointer, like below. */ if (ret < 0) return -1; } /* All OPEN option is parsed. Check capability when strict compare flag is enabled.*/ if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) { /* If Unsupported Capability exists. */ if (error != error_data) { bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, error - error_data); return -1; } /* Check local capability does not negotiated with remote peer. */ if (! strict_capability_same (peer)) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL); return -1; } } /* Check there are no common AFI/SAFIs and send Unsupported Capability error. */ if (*mp_capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP][SAFI_ENCAP] && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]) { plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " "overlap with received MP capabilities", peer->host); if (error != error_data) bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, error - error_data); else bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL); return -1; } } return 0; }
/* Zebra server IPv4 prefix delete function. */ static int zread_ipv4_delete (struct zserv *client, u_short length) { int i; struct stream *s; struct zapi_ipv4 api; struct in_addr nexthop, *nexthop_p; unsigned long ifindex; struct prefix_ipv4 p; u_char nexthop_num; u_char nexthop_type; u_char ifname_len; s = client->ibuf; ifindex = 0; nexthop.s_addr = 0; nexthop_p = NULL; /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); api.safi = stream_getw (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { nexthop_num = stream_getc (s); for (i = 0; i < nexthop_num; i++) { nexthop_type = stream_getc (s); switch (nexthop_type) { case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IFNAME: ifname_len = stream_getc (s); stream_forward_getp (s, ifname_len); break; case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); nexthop_p = &nexthop; break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; } } } /* Distance. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; /* Metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, client->rtm_table, api.safi); return 0; }
struct connected * zebra_interface_address_read (int type, struct stream *s) { unsigned int ifindex; struct interface *ifp; struct connected *ifc; struct prefix p, d; int family; int plen; u_char ifc_flags; memset (&p, 0, sizeof(p)); memset (&d, 0, sizeof(d)); /* Get interface index. */ ifindex = stream_getl (s); /* Lookup index. */ ifp = if_lookup_by_index (ifindex); if (ifp == NULL) { zlog_warn ("zebra_interface_address_read(%s): " "Can't find interface by ifindex: %d ", (type == ZEBRA_INTERFACE_ADDRESS_ADD? "ADD" : "DELETE"), ifindex); return NULL; } /* Fetch flag. */ ifc_flags = stream_getc (s); /* Fetch interface address. */ family = p.family = stream_getc (s); plen = prefix_blen (&p); stream_get (&p.u.prefix, s, plen); p.prefixlen = stream_getc (s); /* Fetch destination address. */ stream_get (&d.u.prefix, s, plen); d.family = family; if (type == ZEBRA_INTERFACE_ADDRESS_ADD) { /* N.B. NULL destination pointers are encoded as all zeroes */ ifc = connected_add_by_prefix(ifp, &p,(memconstant(&d.u.prefix,0,plen) ? NULL : &d)); if (ifc != NULL) ifc->flags = ifc_flags; } else if(type == ZEBRA_INTERFACE_ADDRESS_DELETE) { ifc = connected_delete_by_prefix(ifp, &p); } else { zlog(NULL, LOG_CRIT, "line %u, function %s", __LINE__,(__func__ ? __func__ : "?")); zlog_backtrace(LOG_CRIT); return NULL; } return ifc; }
/* Zebra server IPv6 prefix delete function. */ static int zread_ipv6_delete (struct zserv *client, u_short length) { int i; struct stream *s; struct zapi_ipv6 api; struct in6_addr nexthop; unsigned long ifindex; struct prefix_ipv6 p; s = client->ibuf; ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); api.safi = stream_getw (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { u_char nexthop_type; api.nexthop_num = stream_getc (s); for (i = 0; i < api.nexthop_num; i++) { nexthop_type = stream_getc (s); switch (nexthop_type) { case ZEBRA_NEXTHOP_IPV6: stream_get (&nexthop, s, 16); break; case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); break; } } } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table, api.safi); else rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table, api.safi); return 0; }
static int bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) { struct stream *s = BGP_INPUT (peer); struct capability_orf_entry entry; afi_t afi; safi_t safi; u_char type; u_char mode; u_int16_t sm_cap = 0; /* capability send-mode receive */ u_int16_t rm_cap = 0; /* capability receive-mode receive */ int i; /* ORF Entry header */ bgp_capability_mp_data (s, &entry.mpc); entry.num = stream_getc (s); afi = entry.mpc.afi; safi = entry.mpc.safi; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u", peer->host, entry.mpc.afi, entry.mpc.safi); /* Check AFI and SAFI. */ if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi)) { zlog_info ("%s Addr-family %d/%d not supported." " Ignoring the ORF capability", peer->host, entry.mpc.afi, entry.mpc.safi); return 0; } /* validate number field */ if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length) { zlog_info ("%s ORF Capability entry length error," " Cap length %u, num %u", peer->host, hdr->length, entry.num); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } for (i = 0 ; i < entry.num ; i++) { type = stream_getc(s); mode = stream_getc(s); /* ORF Mode error check */ switch (mode) { case ORF_MODE_BOTH: case ORF_MODE_SEND: case ORF_MODE_RECEIVE: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* ORF Type and afi/safi error checks */ /* capcode versus type */ switch (hdr->code) { case CAPABILITY_CODE_ORF: switch (type) { case ORF_TYPE_PREFIX: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } break; case CAPABILITY_CODE_ORF_OLD: switch (type) { case ORF_TYPE_PREFIX_OLD: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* AFI vs SAFI */ if (!((afi == AFI_IP && safi == SAFI_UNICAST) || (afi == AFI_IP && safi == SAFI_MULTICAST) || (afi == AFI_IP6 && safi == SAFI_UNICAST))) { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s ORF capability" " as %s for afi/safi: %d/%d", peer->host, LOOKUP (orf_type_str, type), LOOKUP (orf_mode_str, mode), entry.mpc.afi, safi); if (hdr->code == CAPABILITY_CODE_ORF) { sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; } else if (hdr->code == CAPABILITY_CODE_ORF_OLD) { sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; } else { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } switch (mode) { case ORF_MODE_BOTH: SET_FLAG (peer->af_cap[afi][safi], sm_cap); SET_FLAG (peer->af_cap[afi][safi], rm_cap); break; case ORF_MODE_SEND: SET_FLAG (peer->af_cap[afi][safi], sm_cap); break; case ORF_MODE_RECEIVE: SET_FLAG (peer->af_cap[afi][safi], rm_cap); break; } } return 0; }
static int ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex; struct prefix_ipv6 p; struct in6_addr *nexthop; s = zclient->ibuf; ifindex = 0; nexthop = NULL; memset (&api, 0, sizeof (api)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop = (struct in6_addr *) malloc (api.nexthop_num * sizeof (struct in6_addr)); stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr)); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) { char prefixstr[128], nexthopstr[128]; prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr)); if (nexthop) inet_ntop (AF_INET6, nexthop, nexthopstr, sizeof (nexthopstr)); else snprintf (nexthopstr, sizeof (nexthopstr), "::"); zlog_debug ("Zebra Receive route %s: %s %s nexthop %s ifindex %ld", (command == ZEBRA_IPV6_ROUTE_ADD ? "add" : "delete"), zebra_route_string(api.type), prefixstr, nexthopstr, ifindex); } if (command == ZEBRA_IPV6_ROUTE_ADD) ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p, api.nexthop_num, nexthop); else ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) free (nexthop); return 0; }