Revision 4847a894

View differences:

filter/filter.h
11 11

  
12 12
#include "lib/resource.h"
13 13
#include "lib/ip.h"
14
#include "nest/route.h"
14 15
#include "nest/attrs.h"
15 16

  
16 17
struct f_inst {		/* Instruction */
nest/a-set.c
40 40
struct adata *
41 41
int_set_add(struct linpool *pool, struct adata *list, u32 val)
42 42
{
43
  struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4);
44
  res->length = list->length+4;
43
  int len = list ? list->length : 0;
44
  struct adata *res = lp_alloc(pool, len + sizeof(struct adata) + 4);
45
  res->length = len + 4;
45 46
  * (u32 *) res->data = val;
46
  memcpy((char *) res->data + 4, list->data, list->length);
47
  if (list)
48
    memcpy((char *) res->data + 4, list->data, list->length);
47 49
  return res;
48 50
}
49 51

  
nest/attrs.h
47 47
int int_set_contains(struct adata *list, u32 val);
48 48
struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val);
49 49

  
50
static inline int int_set_get_size(struct adata *list)
51
{ return list->length / 4; }
52

  
50 53
#endif
proto/bgp/attrs.c
104 104
}
105 105

  
106 106
static int
107
bgp_check_aggregator(struct bgp_proto *p UNUSED, UNUSED byte *a, int len)
107
bgp_check_aggregator(struct bgp_proto *p, UNUSED byte *a, int len)
108 108
{
109 109
  int exp_len = (bgp_as4_support && p->as4_support) ? 8 : 6;
110 110
  
......
112 112
}
113 113

  
114 114
static int
115
bgp_check_cluster_list(struct bgp_proto *p UNUSED, UNUSED byte *a, int len)
116
{
117
  return ((len % 4) == 0) ? 0 : 5;
118
}
119

  
120
static int
115 121
bgp_check_reach_nlri(struct bgp_proto *p UNUSED, byte *a UNUSED, int len UNUSED)
116 122
{
117 123
#ifdef IPV6
......
150 156
    bgp_check_aggregator, NULL },
151 157
  { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET, 1,	/* BA_COMMUNITY */
152 158
    NULL, NULL },
153
  { NULL, },									/* BA_ORIGINATOR_ID */
154
  { NULL, },									/* BA_CLUSTER_LIST */
159
  { "originator_id", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0,				/* BA_ORIGINATOR_ID */
160
    NULL, NULL },
161
  { "cluster_list", -1, BAF_OPTIONAL, EAF_TYPE_INT_SET, 0,			/* BA_CLUSTER_LIST */
162
    bgp_check_cluster_list, NULL }, 
155 163
  { NULL, },									/* BA_DPA */
156 164
  { NULL, },									/* BA_ADVERTISER */
157 165
  { NULL, },									/* BA_RCID_PATH */
......
173 181

  
174 182
#define ATTR_KNOWN(code) ((code) < ARRAY_SIZE(bgp_attr_table) && bgp_attr_table[code].name)
175 183

  
176
static byte *
177
bgp_set_attr(eattr *e, struct linpool *pool, unsigned attr, unsigned val)
184
static inline struct adata *
185
bgp_alloc_adata(struct linpool *pool, unsigned len)
186
{
187
  struct adata *ad = lp_alloc(pool, sizeof(struct adata) + len);
188
  ad->length = len;
189
  return ad;
190
}
191

  
192
static void
193
bgp_set_attr(eattr *e, unsigned attr, uintptr_t val)
178 194
{
179 195
  ASSERT(ATTR_KNOWN(attr));
180 196
  e->id = EA_CODE(EAP_BGP, attr);
181 197
  e->type = bgp_attr_table[attr].type;
182 198
  e->flags = bgp_attr_table[attr].expected_flags;
183 199
  if (e->type & EAF_EMBEDDED)
184
    {
185
      e->u.data = val;
186
      return NULL;
187
    }
200
    e->u.data = val;
188 201
  else
189
    {
190
      e->u.ptr = lp_alloc(pool, sizeof(struct adata) + val);
191
      e->u.ptr->length = val;
192
      return e->u.ptr->data;
193
    }
202
    e->u.ptr = (struct adata *) val;
194 203
}
195 204

  
196
byte *
197
bgp_attach_attr(ea_list **to, struct linpool *pool, unsigned attr, unsigned val)
205
static byte *
206
bgp_set_attr_wa(eattr *e, struct linpool *pool, unsigned attr, unsigned len)
207
{
208
  struct adata *ad = bgp_alloc_adata(pool, len);
209
  bgp_set_attr(e, attr, (uintptr_t) ad);
210
  return ad->data;
211
}
212

  
213
void
214
bgp_attach_attr(ea_list **to, struct linpool *pool, unsigned attr, uintptr_t val)
198 215
{
199 216
  ea_list *a = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
200 217
  a->next = *to;
201 218
  *to = a;
202 219
  a->flags = EALF_SORTED;
203 220
  a->count = 1;
204
  return bgp_set_attr(a->attrs, pool, attr, val);
221
  bgp_set_attr(a->attrs, attr, val);
222
}
223

  
224
byte *
225
bgp_attach_attr_wa(ea_list **to, struct linpool *pool, unsigned attr, unsigned len)
226
{
227
  struct adata *ad = bgp_alloc_adata(pool, len);
228
  bgp_attach_attr(to, pool, attr, (uintptr_t) ad);
229
  return ad->data;
205 230
}
206 231

  
207 232
static int
......
713 738
  bgp_schedule_packet(p->conn, PKT_UPDATE);
714 739
}
715 740

  
741

  
716 742
static int
717 743
bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool)
718 744
{
......
725 751
  ea->flags = EALF_SORTED;
726 752
  ea->count = 4;
727 753

  
728
  bgp_set_attr(ea->attrs, pool, BA_ORIGIN,
754
  bgp_set_attr(ea->attrs, BA_ORIGIN,
729 755
       ((rta->source == RTS_OSPF_EXT1) || (rta->source == RTS_OSPF_EXT2)) ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
730 756

  
731 757
  if (p->is_internal)
732
    bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, 0);
758
    bgp_set_attr_wa(ea->attrs+1, pool, BA_AS_PATH, 0);
733 759
  else
734 760
    {
735
      z = bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, bgp_as4_support ? 6 : 4);
761
      z = bgp_set_attr_wa(ea->attrs+1, pool, BA_AS_PATH, bgp_as4_support ? 6 : 4);
736 762
      z[0] = AS_PATH_SEQUENCE;
737 763
      z[1] = 1;				/* 1 AS */
738 764

  
......
742 768
	put_u16(z+2, p->local_as);
743 769
    }
744 770

  
745
  z = bgp_set_attr(ea->attrs+2, pool, BA_NEXT_HOP, sizeof(ip_addr));
771
  z = bgp_set_attr_wa(ea->attrs+2, pool, BA_NEXT_HOP, sizeof(ip_addr));
746 772
  if (p->cf->next_hop_self ||
747 773
      !p->is_internal ||
748 774
      rta->dest != RTD_ROUTER)
......
755 781
  else
756 782
    *(ip_addr *)z = e->attrs->gw;
757 783

  
758
  bgp_set_attr(ea->attrs+3, pool, BA_LOCAL_PREF, 0);
784
  bgp_set_attr(ea->attrs+3, BA_LOCAL_PREF, 0);
759 785

  
760 786
  return 0;				/* Leave decision to the filters */
761 787
}
762 788

  
763
static ea_list *
764
bgp_path_prepend(struct linpool *pool, eattr *a, ea_list *old, int as)
789

  
790
static inline int
791
bgp_as_path_loopy(struct bgp_proto *p, rta *a)
792
{
793
  eattr *e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
794
  return (e && as_path_is_member(e->u.ptr, p->local_as));
795
}
796

  
797
static inline int
798
bgp_originator_id_loopy(struct bgp_proto *p, rta *a)
765 799
{
766
  struct ea_list *e = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
767
  struct adata *olda = a->u.ptr;
768

  
769
  e->next = old;
770
  e->flags = EALF_SORTED;
771
  e->count = 1;
772
  e->attrs[0].id = EA_CODE(EAP_BGP, BA_AS_PATH);
773
  e->attrs[0].flags = BAF_TRANSITIVE;
774
  e->attrs[0].type = EAF_TYPE_AS_PATH;
775
  e->attrs[0].u.ptr = as_path_prepend(pool, olda, as);
776
  return e;
800
  eattr *e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
801
  return (e && (e->u.data == p->local_id));
802
}
803

  
804
static inline int
805
bgp_cluster_list_loopy(struct bgp_proto *p, rta *a)
806
{
807
  eattr *e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST));
808
  return (e && p->rr_client && int_set_contains(e->u.ptr, p->rr_cluster_id));
809
}
810

  
811

  
812
static inline void
813
bgp_path_prepend(rte *e, ea_list **attrs, struct linpool *pool, u32 as)
814
{
815
  eattr *a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
816
  bgp_attach_attr(attrs, pool, BA_AS_PATH, (uintptr_t) as_path_prepend(pool, a->u.ptr, as));
817
}
818

  
819
static inline void
820
bgp_cluster_list_prepend(rte *e, ea_list **attrs, struct linpool *pool, u32 cid)
821
{
822
  eattr *a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST));
823
  bgp_attach_attr(attrs, pool, BA_CLUSTER_LIST, (uintptr_t) int_set_add(pool, a ? a->u.ptr : NULL, cid));
777 824
}
778 825

  
779 826
static int
780
bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool)
827
bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool, int rr)
781 828
{
782 829
  eattr *a;
783 830

  
784
  if (!p->is_internal && (a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH))))
785
    *attrs = bgp_path_prepend(pool, a, *attrs, p->local_as);
831
  if (!p->is_internal)
832
    bgp_path_prepend(e, attrs, pool, p->local_as);
786 833

  
787 834
  a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
788 835
  if (a && (p->is_internal || (!p->is_internal && e->attrs->iface == p->neigh->iface)))
......
792 839
  else
793 840
    {
794 841
      /* Need to create new one */
795
      *(ip_addr *) bgp_attach_attr(attrs, pool, BA_NEXT_HOP, sizeof(ip_addr)) = p->local_addr;
842
      bgp_attach_attr_ip(attrs, pool, BA_NEXT_HOP, p->local_addr);
843
    }
844

  
845
  if (rr)
846
    {
847
      /* Handling route reflection, RFC 4456 */
848
      struct bgp_proto *src = (struct bgp_proto *) e->attrs->proto;
849

  
850
      a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
851
      if (!a)
852
	bgp_attach_attr(attrs, pool, BA_ORIGINATOR_ID, src->remote_id);
853

  
854
      /* We attach proper cluster ID according to whether the route is entering or leaving the cluster */
855
      bgp_cluster_list_prepend(e, attrs, pool, src->rr_client ? src->rr_cluster_id : p->rr_cluster_id);
856

  
857
      /* Two RR clients with different cluster ID, hmmm */
858
      if (src->rr_client && p->rr_client && (src->rr_cluster_id != p->rr_cluster_id))
859
	bgp_cluster_list_prepend(e, attrs, pool, p->rr_cluster_id);
796 860
    }
797 861

  
798 862
  return 0;				/* Leave decision to the filters */
......
809 873
    return -1;
810 874
  if (new_bgp)
811 875
    {
876
      /* We should check here for cluster list loop, because the receiving BGP instance
877
	 might have different cluster ID  */
878
      if (bgp_cluster_list_loopy(p, e->attrs))
879
	return -1;
880

  
812 881
      if (p->local_as == new_bgp->local_as && p->is_internal && new_bgp->is_internal)
813
	return -1;			/* Don't redistribute internal routes with IBGP */
814
      return bgp_update_attrs(p, e, attrs, pool);
882
	{
883
	  /* Redistribution of internal routes with IBGP */
884
	  if (p->rr_client || new_bgp->rr_client)
885
	    /* Route reflection, RFC 4456 */
886
	    return bgp_update_attrs(p, e, attrs, pool, 1);
887
	  else
888
	    return -1;
889
	}
890
      else
891
	return bgp_update_attrs(p, e, attrs, pool, 0);
815 892
    }
816 893
  else
817 894
    return bgp_create_attrs(p, e, attrs, pool);
......
835 912
  if (n < o)
836 913
    return 0;
837 914

  
838
  /* Use AS path lengths */
915
  /* RFC 4271 9.1.2.2. a)  Use AS path lengths */
839 916
  if (new_bgp->cf->compare_path_lengths || old_bgp->cf->compare_path_lengths)
840 917
    {
841 918
      x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
......
848 925
	return 0;
849 926
    }
850 927

  
851
  /* Use origins */
928
  /* RFC 4271 9.1.2.2. b) Use origins */
852 929
  x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN));
853 930
  y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN));
854 931
  n = x ? x->u.data : ORIGIN_INCOMPLETE;
......
858 935
  if (n > o)
859 936
    return 0;
860 937

  
861
  /* Compare MED's */
938
  /* RFC 4271 9.1.2.2. c) Compare MED's */
862 939
  x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
863 940
  y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
864 941
  n = x ? x->u.data : new_bgp->cf->default_med;
......
868 945
  if (n > o)
869 946
    return 0;
870 947

  
871
  /* A tie breaking procedure according to RFC 1771, section 9.1.2.1 */
872
  /* We don't have interior distances */
873
  /* We prefer external peers */
948
  /* RFC 4271 9.1.2.2. d) Prefer external peers */
874 949
  if (new_bgp->is_internal > old_bgp->is_internal)
875 950
    return 0;
876 951
  if (new_bgp->is_internal < old_bgp->is_internal)
877 952
    return 1;
878
  /* Finally we compare BGP identifiers */
879
  return (new_bgp->remote_id < old_bgp->remote_id);
880
}
881 953

  
882
static int
883
bgp_path_loopy(struct bgp_proto *p, eattr *a)
884
{
885
  return as_path_is_member(a->u.ptr, p->local_as);
886
}
954
  /* Skipping RFC 4271 9.1.2.2. e) */
955
  /* We don't have interior distances */
956

  
957
  /* RFC 4456 9. b) Compare cluster list lengths */
958
  x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST));
959
  y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST));
960
  n = x ? int_set_get_size(x->u.ptr) : 0;
961
  o = y ? int_set_get_size(y->u.ptr) : 0;
962
  if (n < o)
963
    return 1;
964
  if (n > o)
965
    return 0;
966

  
967
  /* RFC 4271 9.1.2.2. f) Compare BGP identifiers */
968
  /* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighor ID */
969
  x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
970
  y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
971
  n = x ? x->u.data : new_bgp->remote_id;
972
  o = y ? y->u.data : old_bgp->remote_id;
973
  if (n < o)
974
    return 1;
975
  if (n > o)
976
    return 0;
887 977

  
888 978

  
979
  /* RFC 4271 9.1.2.2. g) Compare peer IP adresses */
980
  return (ipa_compare(new_bgp->cf->remote_ip, old_bgp->cf->remote_ip) < 0);
981
}
982

  
889 983
static struct adata *
890 984
bgp_aggregator_convert_to_new(struct adata *old, struct linpool *pool)
891 985
{
......
916 1010
}
917 1011

  
918 1012

  
919
/* Reconstruct 4B AS_PATH and AGGREGATOR according to RFC4893 4.2.3 */
1013
/* Reconstruct 4B AS_PATH and AGGREGATOR according to RFC 4893 4.2.3 */
920 1014
static void
921 1015
bgp_reconstruct_4b_atts(struct bgp_proto *p, rta *a, struct linpool *pool)
922 1016
{
......
1159 1253
    bgp_remove_as4_attrs(bgp, a);
1160 1254

  
1161 1255
  /* If the AS path attribute contains our AS, reject the routes */
1162
  e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
1163
  if (e && bgp_path_loopy(bgp, e))
1164
    {
1165
      DBG("BGP: Path loop!\n");
1166
      return NULL;
1167
    }
1256
  if (bgp_as_path_loopy(bgp, a))
1257
    goto loop;
1258

  
1259
  /* Two checks for IBGP loops caused by route reflection, RFC 4456 */ 
1260
  if (bgp_originator_id_loopy(bgp, a) ||
1261
      bgp_cluster_list_loopy(bgp, a))
1262
    goto loop;
1168 1263

  
1169 1264
  /* If there's no local preference, define one */
1170 1265
  if (!(seen[0] && (1 << BA_LOCAL_PREF)))
1171 1266
    bgp_attach_attr(&a->eattrs, pool, BA_LOCAL_PREF, 0);
1172 1267
  return a;
1173 1268

  
1269
loop:
1270
  DBG("BGP: Path loop!\n");
1271
  return NULL;
1272

  
1174 1273
malformed:
1175 1274
  bgp_error(conn, 3, 1, NULL, 0);
1176 1275
  return NULL;
proto/bgp/bgp.c
485 485
  p->local_id = cf->c.global->router_id;
486 486
  p->next_hop = cf->multihop ? cf->multihop_via : cf->remote_ip;
487 487
  p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY);
488

  
489
  if (cf->rr_client)
490
    {
491
      p->rr_cluster_id = cf->rr_cluster_id ? cf->rr_cluster_id : p->local_id;
492
      p->rr_client = cf->rr_client;
493
    }
494

  
488 495
  if (!p->neigh)
489 496
    {
490 497
      log(L_ERR "%s: Invalid next hop %I", p->p.name, p->next_hop);
......
633 640
    cf_error("Local AS number out of range");
634 641
  if (!bgp_as4_support && (c->remote_as > 0xFFFF))
635 642
    cf_error("Neighbor AS number out of range");
643
  if ((c->local_as != c->remote_as) && (c->rr_client))
644
    cf_error("Only internal neighbor can be RR client");
636 645
}
637 646

  
638 647
static void
proto/bgp/bgp.h
25 25
  int compare_path_lengths;		/* Use path lengths when selecting best route */
26 26
  u32 default_local_pref;		/* Default value for LOCAL_PREF attribute */
27 27
  u32 default_med;			/* Default value for MULTI_EXIT_DISC attribute */
28
  u32 rr_cluster_id;			/* Route reflector cluster ID, if different from local ID */
29
  int rr_client;			/* Whether neighbor is RR client of me */
28 30
  unsigned connect_retry_time;
29 31
  unsigned hold_time, initial_hold_time;
30 32
  unsigned keepalive_time;
......
60 62
  int as4_support;			/* Peer supports 4B AS numbers [RFC4893] */
61 63
  u32 local_id;				/* BGP identifier of this router */
62 64
  u32 remote_id;			/* BGP identifier of the neighbor */
65
  u32 rr_cluster_id;			/* Route reflector cluster ID */
66
  int rr_client;			/* Whether neighbor is RR client of me */
63 67
  struct bgp_conn *conn;		/* Connection we have established */
64 68
  struct bgp_conn outgoing_conn;	/* Outgoing connection we're working with */
65 69
  struct bgp_conn incoming_conn;	/* Incoming connection we have neither accepted nor rejected yet */
......
121 125

  
122 126
/* attrs.c */
123 127

  
124
byte *bgp_attach_attr(struct ea_list **to, struct linpool *, unsigned attr, unsigned val);
128
void bgp_attach_attr(struct ea_list **to, struct linpool *pool, unsigned attr, uintptr_t val);
129
byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned attr, unsigned len);
125 130
struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory);
126 131
int bgp_get_attr(struct eattr *e, byte *buf);
127 132
int bgp_rte_better(struct rte *, struct rte *);
......
132 137
void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck);
133 138
void bgp_get_route_info(struct rte *, byte *buf, struct ea_list *attrs);
134 139

  
140
inline static void bgp_attach_attr_ip(struct ea_list **to, struct linpool *pool, unsigned attr, ip_addr a)
141
{ *(ip_addr *) bgp_attach_attr_wa(to, pool, attr, sizeof(ip_addr)) = a; }
142

  
135 143
/* packets.c */
136 144

  
137 145
void bgp_schedule_packet(struct bgp_conn *conn, int type);
proto/bgp/config.Y
20 20
	MULTIHOP, STARTUP, VIA, NEXT, HOP, SELF, DEFAULT, PATH, METRIC,
21 21
	ERROR, START, DELAY, FORGET, WAIT, DISABLE, AFTER,
22 22
	BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN, BGP_NEXT_HOP,
23
	BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS, PASSWORD)
23
	BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS,
24
	PASSWORD, RR, CLIENT, CLUSTER, ID)
24 25

  
25 26
CF_GRAMMAR
26 27

  
......
38 39
     BGP_CFG->error_amnesia_time = 300;
39 40
     BGP_CFG->error_delay_time_min = 60;
40 41
     BGP_CFG->error_delay_time_max = 300;
41
     BGP_CFG->password = NULL;
42 42
 }
43 43
 ;
44 44

  
......
52 52
     BGP_CFG->remote_ip = $3;
53 53
     BGP_CFG->remote_as = $5;
54 54
   }
55
 | bgp_proto RR CLUSTER ID expr ';' { BGP_CFG->rr_cluster_id = $5; }
56
 | bgp_proto RR CLIENT ';' { BGP_CFG->rr_client = 1; }
55 57
 | bgp_proto HOLD TIME expr ';' { BGP_CFG->hold_time = $4; }
56 58
 | bgp_proto STARTUP HOLD TIME expr ';' { BGP_CFG->initial_hold_time = $5; }
57 59
 | bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; }
proto/bgp/packets.c
193 193
  if ((buck = p->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
194 194
    {
195 195
      DBG("Withdrawn routes:\n");
196
      tmp = bgp_attach_attr(&ea, bgp_linpool, BA_MP_UNREACH_NLRI, remains-8);
196
      tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_UNREACH_NLRI, remains-8);
197 197
      *tmp++ = 0;
198 198
      *tmp++ = BGP_AF_IPV6;
199 199
      *tmp++ = 1;
......
218 218
	  size = bgp_encode_attrs(p, w, buck->eattrs, 1024);
219 219
	  w += size;
220 220
	  remains -= size;
221
	  tstart = tmp = bgp_attach_attr(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
221
	  tstart = tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
222 222
	  *tmp++ = 0;
223 223
	  *tmp++ = BGP_AF_IPV6;
224 224
	  *tmp++ = 1;
......
702 702
      /* Create fake NEXT_HOP attribute */
703 703
      if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2)
704 704
	goto bad;
705
      memcpy(bgp_attach_attr(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, 16), x+1, 16);
705
      bgp_attach_attr_ip(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, x[1]);
706 706
      len -= *x + 2;
707 707
      x += *x + 1;
708 708

  

Also available in: Unified diff