Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / proto / bgp / attrs.c @ 6b3f1a54

History | View | Annotate | Download (78.5 KB)

1
/*
2
 *        BIRD -- BGP Attributes
3
 *
4
 *        (c) 2000 Martin Mares <mj@ucw.cz>
5
 *        (c) 2008--2016 Ondrej Zajicek <santiago@crfreenet.org>
6
 *        (c) 2008--2016 CZ.NIC z.s.p.o.
7
 *
8
 *        Can be freely distributed and used under the terms of the GNU GPL.
9
 */
10

    
11
#undef LOCAL_DEBUG
12

    
13
#include <stdlib.h>
14
#include <string.h>
15
#include <stdio.h>
16

    
17
#include "nest/bird.h"
18
#include "nest/iface.h"
19
#include "nest/protocol.h"
20
#include "nest/route.h"
21
#include "nest/attrs.h"
22
#include "conf/conf.h"
23
#include "lib/resource.h"
24
#include "lib/string.h"
25
#include "lib/unaligned.h"
26

    
27
#include "bgp.h"
28

    
29
/*
30
 *   UPDATE message error handling
31
 *
32
 * All checks from RFC 4271 6.3 are done as specified with these exceptions:
33
 *  - The semantic check of an IP address from NEXT_HOP attribute is missing.
34
 *  - Checks of some optional attribute values are missing.
35
 *  - Syntactic and semantic checks of NLRIs (done in DECODE_PREFIX())
36
 *    are probably inadequate.
37
 *
38
 * Loop detection based on AS_PATH causes updates to be withdrawn. RFC
39
 * 4271 does not explicitly specifiy the behavior in that case.
40
 *
41
 * Loop detection related to route reflection (based on ORIGINATOR_ID
42
 * and CLUSTER_LIST) causes updates to be withdrawn. RFC 4456 8
43
 * specifies that such updates should be ignored, but that is generally
44
 * a bad idea.
45
 *
46
 * BGP attribute table has several hooks:
47
 *
48
 * export - Hook that validates and normalizes attribute during export phase.
49
 * Receives eattr, may modify it (e.g., sort community lists for canonical
50
 * representation), UNSET() it (e.g., skip empty lists), or WITHDRAW() it if
51
 * necessary. May assume that eattr has value valid w.r.t. its type, but may be
52
 * invalid w.r.t. BGP constraints. Optional.
53
 *
54
 * encode - Hook that converts internal representation to external one during
55
 * packet writing. Receives eattr and puts it in the buffer (including attribute
56
 * header). Returns number of bytes, or -1 if not enough space. May assume that
57
 * eattr has value valid w.r.t. its type and validated by export hook. Mandatory
58
 * for all known attributes that exist internally after export phase (i.e., all
59
 * except pseudoattributes MP_(UN)REACH_NLRI).
60
 *
61
 * decode - Hook that converts external representation to internal one during
62
 * packet parsing. Receives attribute data in buffer, validates it and adds
63
 * attribute to ea_list. If data are invalid, steps DISCARD(), WITHDRAW() or
64
 * bgp_parse_error() may be used to escape. Mandatory for all known attributes.
65
 *
66
 * format - Optional hook that converts eattr to textual representation.
67
 */
68

    
69
struct bgp_attr_desc {
70
    const char *name;
71
    uint type;
72
    uint flags;
73
    void (*export)(struct bgp_export_state *s, eattr *a);
74
    int  (*encode)(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
75
    void (*decode)(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to);
76
    void (*format)(eattr *ea, byte *buf, uint size);
77
};
78

    
79
static const struct bgp_attr_desc bgp_attr_table[];
80

    
81
static inline int bgp_attr_known(uint code);
82

    
83

    
84
/**
85
 * This function initialize the map used for the RT and the ASLoad map
86
 *
87
 * @author Mattia Milani
88
 */
89
void initRTmap(){
90
    //Map init
91
    map_init(&RTmap);
92
    map_init(&ExternalDestinationMap);
93
    map_init(&ASLoad_map);
94
    //Variable setting
95
    esportoDestinazioni = 0;
96
    total_number_of_update_sent = 0;
97
}
98

    
99
/**
100
 * Init function for the init of a RT element to be loaded in the data structure
101
 * @param dest Destination addr
102
 * @param l Load
103
 * @param inter Define if an addr is intern or extern
104
 * @return Return the RTable element
105
 */
106
RTable
107
initRTableElement(net_addr *dest, int l, int inter){
108
    RTable element;
109
    element.interno = inter;
110
    element.d = dest;
111
    map_init(&element.NH);
112
    map_init(&element.loadin);
113
    element.load = l;
114
    return element;
115
}
116

    
117
eattr *
118
        bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintptr_t val)
119
{
120
ASSERT(bgp_attr_known(code));
121

    
122
ea_list *a = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
123
eattr *e = &a->attrs[0];
124

    
125
a->flags = EALF_SORTED;
126
a->count = 1;
127
a->next = *attrs;
128
*attrs = a;
129

    
130
e->id = EA_CODE(EAP_BGP, code);
131
e->type = bgp_attr_table[code].type;
132
e->flags = flags;
133

    
134
if (e->type & EAF_EMBEDDED)
135
e->u.data = (u32) val;
136
else
137
e->u.ptr = (struct adata *) val;
138

    
139
return e;
140
}
141

    
142
#define REPORT(msg, args...) \
143
  ({ log(L_REMOTE "%s: " msg, s->proto->p.name, ## args); })
144

    
145
#define DISCARD(msg, args...) \
146
  ({ REPORT(msg, ## args); return; })
147

    
148
#define WITHDRAW(msg, args...) \
149
  ({ REPORT(msg, ## args); s->err_withdraw = 1; return; })
150

    
151
#define UNSET(a) \
152
  ({ a->type = EAF_TYPE_UNDEF; return; })
153

    
154
#define NEW_BGP                "Discarding %s attribute received from AS4-aware neighbor"
155
#define BAD_EBGP        "Discarding %s attribute received from EBGP neighbor"
156
#define BAD_LENGTH        "Malformed %s attribute - invalid length (%u)"
157
#define BAD_VALUE        "Malformed %s attribute - invalid value (%u)"
158
#define NO_MANDATORY        "Missing mandatory %s attribute"
159

    
160

    
161
static inline int
162
bgp_put_attr_hdr3(byte *buf, uint code, uint flags, uint len)
163
{
164
    *buf++ = flags;
165
    *buf++ = code;
166
    *buf++ = len;
167
    return 3;
168
}
169

    
170
static inline int
171
bgp_put_attr_hdr4(byte *buf, uint code, uint flags, uint len)
172
{
173
    *buf++ = flags | BAF_EXT_LEN;
174
    *buf++ = code;
175
    put_u16(buf, len);
176
    return 4;
177
}
178

    
179
static inline int
180
bgp_put_attr_hdr(byte *buf, uint code, uint flags, uint len)
181
{
182
    if (len < 256)
183
        return bgp_put_attr_hdr3(buf, code, flags, len);
184
    else
185
        return bgp_put_attr_hdr4(buf, code, flags, len);
186
}
187

    
188
static int
189
bgp_encode_u8(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
190
{
191
    if (size < (3+1))
192
        return -1;
193

    
194
    bgp_put_attr_hdr3(buf, EA_ID(a->id), a->flags, 1);
195
    buf[3] = a->u.data;
196

    
197
    return 3+1;
198
}
199

    
200
static int
201
bgp_encode_u32(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
202
{
203
    if (size < (3+4))
204
        return -1;
205

    
206
    bgp_put_attr_hdr3(buf, EA_ID(a->id), a->flags, 4);
207
    put_u32(buf+3, a->u.data);
208

    
209
    return 3+4;
210
}
211

    
212
static int
213
bgp_encode_u32s(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
214
{
215
    uint len = a->u.ptr->length;
216

    
217
    if (size < (4+len))
218
        return -1;
219

    
220
    uint hdr = bgp_put_attr_hdr(buf, EA_ID(a->id), a->flags, len);
221
    put_u32s(buf + hdr, (u32 *) a->u.ptr->data, len / 4);
222

    
223
    return hdr + len;
224
}
225

    
226
static int
227
bgp_put_attr(byte *buf, uint size, uint code, uint flags, byte *data, uint len)
228
{
229
    if (size < (4+len))
230
        return -1;
231

    
232
    uint hdr = bgp_put_attr_hdr(buf, code, flags, len);
233
    memcpy(buf + hdr, data, len);
234

    
235
    return hdr + len;
236
}
237

    
238
static int
239
bgp_encode_raw(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
240
{
241
    return bgp_put_attr(buf, size, EA_ID(a->id), a->flags, a->u.ptr->data, a->u.ptr->length);
242
}
243

    
244

    
245
/*
246
 *        Attribute hooks
247
 */
248

    
249
static void
250
bgp_export_origin(struct bgp_export_state *s, eattr *a)
251
{
252
    if (a->u.data > 2)
253
        WITHDRAW(BAD_VALUE, "ORIGIN", a->u.data);
254
}
255

    
256
static void
257
bgp_decode_origin(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
258
{
259
    if (len != 1)
260
        WITHDRAW(BAD_LENGTH, "ORIGIN", len);
261

    
262
    if (data[0] > 2)
263
        WITHDRAW(BAD_VALUE, "ORIGIN", data[0]);
264

    
265
    bgp_set_attr_u32(to, s->pool, BA_ORIGIN, flags, data[0]);
266
}
267

    
268
static void
269
bgp_format_origin(eattr *a, byte *buf, uint size UNUSED)
270
{
271
    static const char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
272

    
273
    bsprintf(buf, (a->u.data <= 2) ? bgp_origin_names[a->u.data] : "?");
274
}
275

    
276

    
277
static int
278
bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
279
{
280
    byte *data = a->u.ptr->data;
281
    uint len = a->u.ptr->length;
282

    
283
    if (!s->as4_session)
284
    {
285
        /* Prepare 16-bit AS_PATH (from 32-bit one) in a temporary buffer */
286
        byte *src = data;
287
        data = alloca(len);
288
        len = as_path_32to16(data, src, len);
289
    }
290

    
291
    return bgp_put_attr(buf, size, BA_AS_PATH, a->flags, data, len);
292
}
293

    
294
static int
295
bgp_encode_nhs_list(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
296
{
297
    byte *data = a->u.ptr->data;
298
    uint len = a->u.ptr->length;
299

    
300
    if (!s->as4_session)
301
    {
302
        /* Prepare 16-bit AS_PATH (from 32-bit one) in a temporary buffer */
303
        byte *src = data;
304
        data = alloca(len);
305
        len = as_path_32to16(data, src, len);
306
    }
307

    
308
    return bgp_put_attr(buf, size, BA_AS_NH_LIST, a->flags, data, len);
309
}
310

    
311
/**
312
 * Function to encode the load to the correct attribute
313
 * @param s bgp write state
314
 * @param a attribute
315
 * @param buf buffer
316
 * @param size size of the attribute
317
 * @return
318
 */
319
static int
320
bgp_encode_as_load(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
321
{
322
    //Pointer to the data contained in the attribute
323
    byte *data = a->u.ptr->data;
324
    //Actual length of the attribute data
325
    uint len = a->u.ptr->length;
326

    
327
    if (!s->as4_session)
328
    {
329
        // Prepare 16-bit AS_PATH (from 32-bit one) in a temporary buffer
330
        byte *src = data;
331
        data = alloca(len);
332
        len = as_path_32to16(data, src, len);
333
    }
334

    
335
    return bgp_put_attr(buf, size, BA_AS_LOAD, a->flags, data, len);
336
}
337

    
338
/**
339
 * Function to decode the as path passed from the packet
340
 * @param s
341
 * @param code
342
 * @param flags
343
 * @param data
344
 * @param len
345
 * @param to
346
 */
347
static void
348
bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
349
{
350
    struct bgp_proto *p = s->proto;
351
    int as_length = s->as4_session ? 4 : 2;
352
    int as_confed = p->cf->confederation && p->is_interior;
353
    char err[128];
354

    
355
    //Catch malformed attribute
356
    if (!as_path_valid(data, len, as_length, as_confed, err, sizeof(err)))
357
        WITHDRAW("Malformed AS_PATH attribute - %s", err);
358

    
359
    /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
360
    if (p->is_interior && !p->is_internal &&
361
        ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
362
        WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
363

    
364
    if (!s->as4_session)
365
    {
366
        /* Prepare 32-bit AS_PATH (from 16-bit one) in a temporary buffer */
367
        byte *src = data;
368
        data = alloca(2*len);
369
        len = as_path_16to32(data, src, len);
370
    }
371
    char buf2[32];
372
    sprintf(buf2, "%02X%02X%02X%02X",data[2], data[3], data[4], data[5]);
373
    //TODO this data cannot be taken from the attribute data?
374
    ASRicezione = (int)strtol(buf2, NULL, 16);
375
    //log(L_INFO "%d", ASRicezione);
376
    bgp_set_attr_data(to, s->pool, BA_AS_PATH, flags, data, len);
377
}
378

    
379
/**
380
 * Function used to decode the list of NHs take from the packet
381
 * @param s
382
 * @param code
383
 * @param flags
384
 * @param data
385
 * @param len
386
 * @param to
387
 */
388
static void
389
bgp_decode_nhs_list(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
390
{
391
    struct bgp_proto *p = s->proto;
392
    int as_length = s->as4_session ? 4 : 2;
393
    int as_confed = p->cf->confederation && p->is_interior;
394
    char err[128];
395

    
396
    if (!as_path_valid(data, len, as_length, as_confed, err, sizeof(err)))
397
        WITHDRAW("Malformed AS_PATH attribute - %s", err);
398

    
399
    /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
400
    if (p->is_interior && !p->is_internal &&
401
        ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
402
        WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
403

    
404
    if (!s->as4_session)
405
    {
406
        /* Prepare 32-bit AS_PATH (from 16-bit one) in a temporary buffer */
407
        byte *src = data;
408
        data = alloca(2*len);
409
        len = as_path_16to32(data, src, len);
410
    }
411

    
412
    //log(L_INFO "Len: %d", len);
413
    if(len > 0){
414
        numeroNHarrivati = data[1];
415
        //log(L_INFO "Decodifica nh %d:", numeroNHarrivati);
416
        int i = 0;
417
        int k = 2;
418
        /* Check if my as is in the NH list */
419
        for(i = 0;i < data[1]; i++){
420
            /*log(L_INFO "C'è un NH");
421
            *log(L_INFO "data[%d] = %d",i, data[k]);
422
            *log(L_INFO "data[%d] = %d",i, data[k+1]);
423
            *log(L_INFO "data[%d] = %d",i, data[k+2]);
424
            *log(L_INFO "data[%d] = %d",i, data[k+3]);
425
            */
426
            char buf2[32];
427
            sprintf(buf2, "%02X%02X%02X%02X",data[k], data[k+1], data[k+2], data[k+3]);
428
            unsigned int nhLetto = (int)strtol(buf2, NULL, 16);
429
            //log(L_INFO "nh[%d] = %d",i, nhLetto);
430
            k+=4;
431
            if(p->public_as == nhLetto){
432
                //log(L_INFO "Hey io sono il NH");
433
                //I founded that I am in the nh list
434
                sonoIlNH = 1;
435
            }
436
        }
437
    }
438
}
439

    
440
/**
441
 * Function to decode the load data structure from an update packet
442
 * @param s
443
 * @param code
444
 * @param flags
445
 * @param data
446
 * @param len
447
 * @param to
448
 */
449
static void
450
bgp_decode_as_load(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
451
{
452
    //log(L_INFO "SONO IN AS LOAD");
453
    struct bgp_proto *p = s->proto;
454
    int as_length = s->as4_session ? 4 : 2;
455
    int as_confed = p->cf->confederation && p->is_interior;
456
    char err[128];
457

    
458
    if (!as_path_valid(data, len, as_length, as_confed, err, sizeof(err)))
459
        WITHDRAW("Malformed AS_LOAD attribute - %s", err);
460

    
461
    // In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0
462
    if (p->is_interior && !p->is_internal &&
463
        ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
464
        WITHDRAW("Malformed AS_LOAD attribute - %s", "missing initial AS_CONFED_SEQUENCE");
465

    
466
    if (!s->as4_session)
467
    {
468
        // Prepare 32-bit AS_PATH (from 16-bit one) in a temporary buffer
469
        byte *src = data;
470
        data = alloca(2*len);
471
        len = as_path_16to32(data, src, len);
472
    }
473

    
474
    //log(L_INFO "Len: %d", len);
475
    if(len > 0){
476
        //log(L_INFO "Decodifica nh %d:", data[1]);
477
        int i = 0;
478
        int k = 2;
479
        for(i = 0;i < data[1]; i++){
480
            /*log(L_INFO "C'è un AS");
481
            log(L_INFO "data[%d] = %d",i, data[k]);
482
            log(L_INFO "data[%d] = %d",i, data[k+1]);
483
            log(L_INFO "data[%d] = %d",i, data[k+2]);
484
            log(L_INFO "data[%d] = %d",i, data[k+3]);
485
            log(L_INFO "AS => %02X%02X%02X%02X",data[k], data[k+1], data[k+2], data[k+3]);*/
486
            char buf2[32];
487
            sprintf(buf2, "%02X%02X%02X%02X",data[k], data[k+1], data[k+2], data[k+3]);
488
            unsigned int asLetto = (int)strtol(buf2, NULL, 16);
489
            //log(L_INFO "as[%d] = %d",i, asLetto);
490
            k+=4;
491
            i++;
492
            /*log(L_INFO "Load AS");
493
            log(L_INFO "data[%d] = %d",i, data[k]);
494
            log(L_INFO "data[%d] = %d",i, data[k+1]);
495
            log(L_INFO "data[%d] = %d",i, data[k+2]);
496
            log(L_INFO "data[%d] = %d",i, data[k+3]);
497
            log(L_INFO "AS LOAD => %02X%02X%02X%02X",data[k], data[k+1], data[k+2], data[k+3]);*/
498
            sprintf(buf2, "%02X%02X%02X%02X",data[k], data[k+1], data[k+2], data[k+3]);
499
            int loadLetto = (int)strtol(buf2, NULL, 16);
500
            float loadASRileato = *((float *) &loadLetto);
501
            char output[50];
502
            snprintf(output, 50, "%f", loadASRileato);
503
            //log(L_INFO "load[%d] = %s",i, output);
504
            k+=4;
505
            i++;
506

    
507
            /*log(L_INFO "Metrica Load AS");
508
            log(L_INFO "data[%d] = %d",i, data[k]);
509
            log(L_INFO "data[%d] = %d",i, data[k+1]);
510
            log(L_INFO "data[%d] = %d",i, data[k+2]);
511
            log(L_INFO "data[%d] = %d",i, data[k+3]);
512
            log(L_INFO "AS METRIC => %02X%02X%02X%02X",data[k], data[k+1], data[k+2], data[k+3]);*/
513
            sprintf(buf2, "%02X%02X%02X%02X",data[k], data[k+1], data[k+2], data[k+3]);
514
            int metrica = (int)strtol(buf2, NULL, 16);
515
            //log(L_INFO "metrica[%d] = %d",i, metrica);
516
            k+=4;
517

    
518
            char chKeyASLoad[12] = "";
519
            sprintf(chKeyASLoad, "%d", asLetto);
520

    
521
            //Generate an ASLoad element from the data get in this section of the packet
522
            ASLoad ASLoad_ricevuto = {loadASRileato, metrica, 1, NULL};
523
            map_init(&ASLoad_ricevuto.remoteMap);
524

    
525
            //Check if it's already in the data structure
526
            ASLoad *ASLoad_element = map_get(&ASLoad_map, chKeyASLoad);
527
            if (ASLoad_element) {
528
                //log(L_INFO "AS già presente, aggiorno il valore");
529
                if(asLetto != p->public_as && ASLoad_element->metrica < ASLoad_ricevuto.metrica){
530
                    ASLoad_element->load = ASLoad_ricevuto.load;
531
                    ASLoad_element->metrica = ASLoad_ricevuto.metrica;
532
                    //ASLoad_element->changed = 1;
533

    
534
                    //Clean the remote map
535
                    const char *key;
536
                    map_iter_t iter = map_iter(&ASLoad_element->remoteMap);
537
                    while ((key = map_next(&ASLoad_element->remoteMap, &iter))) {
538
                        map_remove(&ASLoad_element->remoteMap, key);
539
                    }
540
                }
541
                if(asLetto == p->public_as && ASLoad_element->metrica < ASLoad_ricevuto.metrica){
542
                    ASLoad_element->metrica = ASLoad_ricevuto.metrica++;
543
                    //ASLoad_element->changed = 1;
544
                    const char *key;
545
                    map_iter_t iter = map_iter(&ASLoad_element->remoteMap);
546

    
547
                    while ((key = map_next(&ASLoad_element->remoteMap, &iter))) {
548
                        map_remove(&ASLoad_element->remoteMap, key);
549
                    }
550
                }
551
            } else {
552
                //log(L_INFO "AS non presente, lo aggiungo");
553
                map_set(&ASLoad_map, chKeyASLoad, ASLoad_ricevuto);
554
            }
555
        }
556
    }
557
}
558

    
559
/**
560
 * Function to encode the NH
561
 * @param s
562
 * @param a
563
 * @param buf
564
 * @param size
565
 * @return
566
 */
567
static int
568
bgp_encode_next_hop(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
569
{
570
    /*
571
     * The NEXT_HOP attribute is used only in traditional (IPv4) BGP. In MP-BGP,
572
     * the next hop is encoded as a part of the MP_REACH_NLRI attribute, so we
573
     * store it and encode it later by AFI-specific hooks.
574
     */
575

    
576
    if (s->channel->afi == BGP_AF_IPV4)
577
    {
578
        ASSERT(a->u.ptr->length == sizeof(ip_addr));
579

    
580
        if (size < (3+4))
581
            return -1;
582

    
583
        bgp_put_attr_hdr3(buf, BA_NEXT_HOP, a->flags, 4);
584
        put_ip4(buf+3, ipa_to_ip4( *(ip_addr *) a->u.ptr->data ));
585

    
586
        return 3+4;
587
    }
588
    else
589
    {
590
        s->mp_next_hop = a;
591
        return 0;
592
    }
593
}
594

    
595
static void
596
bgp_decode_next_hop(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data, uint len, ea_list **to UNUSED)
597
{
598
    if (len != 4)
599
        WITHDRAW(BAD_LENGTH, "NEXT_HOP", len);
600

    
601
    nhKey = 0;
602
    nhKey += data[0] + data[1] + data[2] + data[3];
603

    
604
    /* Semantic checks are done later */
605
    s->ip_next_hop_len = len;
606
    s->ip_next_hop_data = data;
607
}
608

    
609
static void
610
bgp_format_next_hop(eattr *a, byte *buf, uint size UNUSED)
611
{
612
    ip_addr *nh = (void *) a->u.ptr->data;
613
    uint len = a->u.ptr->length;
614

    
615
    ASSERT((len == 16) || (len == 32));
616

    
617
    /* in IPv6, we may have two addresses in NEXT HOP */
618
    if ((len == 16) || ipa_zero(nh[1]))
619
        bsprintf(buf, "%I", nh[0]);
620
    else
621
        bsprintf(buf, "%I %I", nh[0], nh[1]);
622
}
623

    
624

    
625
static void
626
bgp_decode_med(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
627
{
628
    if (len != 4)
629
        WITHDRAW(BAD_LENGTH, "MULTI_EXIT_DISC", len);
630

    
631
    u32 val = get_u32(data);
632
    bgp_set_attr_u32(to, s->pool, BA_MULTI_EXIT_DISC, flags, val);
633
}
634

    
635
//TODO hard todo, use atributes and not variables for those things
636
/**
637
 * Function to decode the load_out in a packet
638
 * @param s
639
 * @param code
640
 * @param flags
641
 * @param data
642
 * @param len
643
 * @param to
644
 */
645
static void
646
bgp_decode_load_out(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
647
{
648
    if (len != 4)
649
        WITHDRAW(BAD_LENGTH, "BA_LOAD_SENDER", len);
650

    
651
    u32 val = get_u32(data);
652
    char output[50];
653
    int v = val;
654
    loadOutRilevato = *((float *) &v);
655
    snprintf(output, 50, "%f", loadOutRilevato);
656
}
657

    
658
static void
659
bgp_export_local_pref(struct bgp_export_state *s, eattr *a)
660
{
661
    if (!s->proto->is_interior && !s->proto->cf->allow_local_pref)
662
        UNSET(a);
663
}
664

    
665
static void
666
bgp_decode_local_pref(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
667
{
668
    if (!s->proto->is_interior && !s->proto->cf->allow_local_pref)
669
        DISCARD(BAD_EBGP, "LOCAL_PREF");
670

    
671
    if (len != 4)
672
        WITHDRAW(BAD_LENGTH, "LOCAL_PREF", len);
673

    
674
    u32 val = get_u32(data);
675
    bgp_set_attr_u32(to, s->pool, BA_LOCAL_PREF, flags, val);
676
}
677

    
678

    
679
static void
680
bgp_decode_atomic_aggr(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data UNUSED, uint len, ea_list **to)
681
{
682
    if (len != 0)
683
        DISCARD(BAD_LENGTH, "ATOMIC_AGGR", len);
684

    
685
    bgp_set_attr_data(to, s->pool, BA_ATOMIC_AGGR, flags, NULL, 0);
686
}
687

    
688
static int
689
bgp_encode_aggregator(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
690
{
691
    byte *data = a->u.ptr->data;
692
    uint len = a->u.ptr->length;
693

    
694
    if (!s->as4_session)
695
    {
696
        /* Prepare 16-bit AGGREGATOR (from 32-bit one) in a temporary buffer */
697
        byte *src = data;
698
        data = alloca(6);
699
        len = aggregator_32to16(data, src);
700
    }
701

    
702
    return bgp_put_attr(buf, size, BA_AGGREGATOR, a->flags, data, len);
703
}
704

    
705
static void
706
bgp_decode_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
707
{
708
    if (len != (s->as4_session ? 8 : 6))
709
        DISCARD(BAD_LENGTH, "AGGREGATOR", len);
710

    
711
    if (!s->as4_session)
712
    {
713
        /* Prepare 32-bit AGGREGATOR (from 16-bit one) in a temporary buffer */
714
        byte *src = data;
715
        data = alloca(8);
716
        len = aggregator_16to32(data, src);
717
    }
718

    
719
    bgp_set_attr_data(to, s->pool, BA_AGGREGATOR, flags, data, len);
720
}
721

    
722
static void
723
bgp_format_aggregator(eattr *a, byte *buf, uint size UNUSED)
724
{
725
    byte *data = a->u.ptr->data;
726

    
727
    bsprintf(buf, "%I4 AS%u", get_ip4(data+4), get_u32(data+0));
728
}
729

    
730

    
731
static void
732
bgp_export_community(struct bgp_export_state *s, eattr *a)
733
{
734
    if (a->u.ptr->length == 0)
735
        UNSET(a);
736

    
737
    a->u.ptr = int_set_sort(s->pool, a->u.ptr);
738
}
739

    
740
static void
741
bgp_decode_community(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
742
{
743
    if (!len || (len % 4))
744
        WITHDRAW(BAD_LENGTH, "COMMUNITY", len);
745

    
746
    struct adata *ad = lp_alloc_adata(s->pool, len);
747
    get_u32s(data, (u32 *) ad->data, len / 4);
748
    bgp_set_attr_ptr(to, s->pool, BA_COMMUNITY, flags, ad);
749
}
750

    
751

    
752
static void
753
bgp_export_originator_id(struct bgp_export_state *s, eattr *a)
754
{
755
    if (!s->proto->is_internal)
756
        UNSET(a);
757
}
758

    
759
static void
760
bgp_decode_originator_id(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
761
{
762
    if (!s->proto->is_internal)
763
        DISCARD(BAD_EBGP, "ORIGINATOR_ID");
764

    
765
    if (len != 4)
766
        WITHDRAW(BAD_LENGTH, "ORIGINATOR_ID", len);
767

    
768
    u32 val = get_u32(data);
769
    bgp_set_attr_u32(to, s->pool, BA_ORIGINATOR_ID, flags, val);
770
}
771

    
772

    
773
static void
774
bgp_export_cluster_list(struct bgp_export_state *s UNUSED, eattr *a)
775
{
776
    if (!s->proto->is_internal)
777
        UNSET(a);
778

    
779
    if (a->u.ptr->length == 0)
780
        UNSET(a);
781
}
782

    
783
static void
784
bgp_decode_cluster_list(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
785
{
786
    if (!s->proto->is_internal)
787
        DISCARD(BAD_EBGP, "CLUSTER_LIST");
788

    
789
    if (!len || (len % 4))
790
        WITHDRAW(BAD_LENGTH, "CLUSTER_LIST", len);
791

    
792
    struct adata *ad = lp_alloc_adata(s->pool, len);
793
    get_u32s(data, (u32 *) ad->data, len / 4);
794
    bgp_set_attr_ptr(to, s->pool, BA_CLUSTER_LIST, flags, ad);
795
}
796

    
797
static void
798
bgp_format_cluster_list(eattr *a, byte *buf, uint size)
799
{
800
    /* Truncates cluster lists larger than buflen, probably not a problem */
801
    int_set_format(a->u.ptr, 0, -1, buf, size);
802
}
803

    
804

    
805
static inline u32
806
get_af3(byte *buf)
807
{
808
    return (get_u16(buf) << 16) | buf[2];
809
}
810

    
811
static void
812
bgp_decode_mp_reach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data, uint len, ea_list **to UNUSED)
813
{
814
    /*
815
     *        2 B        MP_REACH_NLRI data - Address Family Identifier
816
     *        1 B        MP_REACH_NLRI data - Subsequent Address Family Identifier
817
     *        1 B        MP_REACH_NLRI data - Length of Next Hop Network Address
818
     *        var        MP_REACH_NLRI data - Network Address of Next Hop
819
     *        1 B        MP_REACH_NLRI data - Reserved (zero)
820
     *        var        MP_REACH_NLRI data - Network Layer Reachability Information
821
     */
822

    
823
    if ((len < 5) || (len < (5 + (uint) data[3])))
824
    bgp_parse_error(s, 9);
825

    
826
    s->mp_reach_af = get_af3(data);
827
    s->mp_next_hop_len = data[3];
828
    s->mp_next_hop_data = data + 4;
829
    s->mp_reach_len = len - 5 - s->mp_next_hop_len;
830
    s->mp_reach_nlri = data + 5 + s->mp_next_hop_len;
831
}
832

    
833

    
834
static void
835
bgp_decode_mp_unreach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data, uint len, ea_list **to UNUSED)
836
{
837
    /*
838
     *        2 B        MP_UNREACH_NLRI data - Address Family Identifier
839
     *        1 B        MP_UNREACH_NLRI data - Subsequent Address Family Identifier
840
     *        var        MP_UNREACH_NLRI data - Network Layer Reachability Information
841
     */
842

    
843
    if (len < 3)
844
        bgp_parse_error(s, 9);
845

    
846
    s->mp_unreach_af = get_af3(data);
847
    s->mp_unreach_len = len - 3;
848
    s->mp_unreach_nlri = data + 3;
849
}
850

    
851

    
852
static void
853
bgp_export_ext_community(struct bgp_export_state *s, eattr *a)
854
{
855
    a->u.ptr = ec_set_del_nontrans(s->pool, a->u.ptr);
856

    
857
    if (a->u.ptr->length == 0)
858
        UNSET(a);
859

    
860
    ec_set_sort_x(a->u.ptr);
861
}
862

    
863
static void
864
bgp_decode_ext_community(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
865
{
866
    if (!len || (len % 8))
867
        WITHDRAW(BAD_LENGTH, "EXT_COMMUNITY", len);
868

    
869
    struct adata *ad = lp_alloc_adata(s->pool, len);
870
    get_u32s(data, (u32 *) ad->data, len / 4);
871
    bgp_set_attr_ptr(to, s->pool, BA_EXT_COMMUNITY, flags, ad);
872
}
873

    
874

    
875
static void
876
bgp_decode_as4_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
877
{
878
    if (s->as4_session)
879
        DISCARD(NEW_BGP, "AS4_AGGREGATOR");
880

    
881
    if (len != 8)
882
        DISCARD(BAD_LENGTH, "AS4_AGGREGATOR", len);
883

    
884
    bgp_set_attr_data(to, s->pool, BA_AS4_AGGREGATOR, flags, data, len);
885
}
886

    
887
static void
888
bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
889
{
890
    char err[128];
891

    
892
    if (s->as4_session)
893
        DISCARD(NEW_BGP, "AS4_PATH");
894

    
895
    if (len < 6)
896
        DISCARD(BAD_LENGTH, "AS4_PATH", len);
897

    
898
    if (!as_path_valid(data, len, 4, 1, err, sizeof(err)))
899
        DISCARD("Malformed AS4_PATH attribute - %s", err);
900

    
901
    struct adata *a = lp_alloc_adata(s->pool, len);
902
    memcpy(a->data, data, len);
903

    
904
    /* AS_CONFED* segments are invalid in AS4_PATH; RFC 6793 6 */
905
    if (as_path_contains_confed(a))
906
    {
907
        REPORT("Discarding AS_CONFED* segment from AS4_PATH attribute");
908
        a = as_path_strip_confed(s->pool, a);
909
    }
910

    
911
    bgp_set_attr_ptr(to, s->pool, BA_AS4_PATH, flags, a);
912
}
913

    
914
static void
915
bgp_export_large_community(struct bgp_export_state *s, eattr *a)
916
{
917
    if (a->u.ptr->length == 0)
918
        UNSET(a);
919

    
920
    a->u.ptr = lc_set_sort(s->pool, a->u.ptr);
921
}
922

    
923
static void
924
bgp_decode_large_community(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
925
{
926
    if (!len || (len % 12))
927
        WITHDRAW(BAD_LENGTH, "LARGE_COMMUNITY", len);
928

    
929
    struct adata *ad = lp_alloc_adata(s->pool, len);
930
    get_u32s(data, (u32 *) ad->data, len / 4);
931
    bgp_set_attr_ptr(to, s->pool, BA_LARGE_COMMUNITY, flags, ad);
932
}
933

    
934
static void
935
bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a)
936
{
937
    net_addr *n = s->route->net->n.addr;
938
    u32 *labels = (u32 *) a->u.ptr->data;
939
    uint lnum = a->u.ptr->length / 4;
940

    
941
    /* Perhaps we should just ignore it? */
942
    if (!s->mpls)
943
        WITHDRAW("Unexpected MPLS stack");
944

    
945
    /* Empty MPLS stack is not allowed */
946
    if (!lnum)
947
        WITHDRAW("Malformed MPLS stack - empty");
948

    
949
    /* This is ugly, but we must ensure that labels fit into NLRI field */
950
    if ((24*lnum + (net_is_vpn(n) ? 64 : 0) + net_pxlen(n)) > 255)
951
        WITHDRAW("Malformed MPLS stack - too many labels (%u)", lnum);
952

    
953
    for (uint i = 0; i < lnum; i++)
954
    {
955
        if (labels[i] > 0xfffff)
956
            WITHDRAW("Malformed MPLS stack - invalid label (%u)", labels[i]);
957
    }
958
}
959

    
960
static int
961
bgp_encode_mpls_label_stack(struct bgp_write_state *s, eattr *a, byte *buf UNUSED, uint size UNUSED)
962
{
963
    /*
964
     * MPLS labels are encoded as a part of the NLRI in MP_REACH_NLRI attribute,
965
     * so we store MPLS_LABEL_STACK and encode it later by AFI-specific hooks.
966
     */
967

    
968
    s->mpls_labels = a->u.ptr;
969
    return 0;
970
}
971

    
972
static void
973
bgp_decode_mpls_label_stack(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUSED, byte *data UNUSED, uint len UNUSED, ea_list **to UNUSED)
974
{
975
    DISCARD("Discarding received attribute #0");
976
}
977

    
978
static void
979
bgp_format_mpls_label_stack(eattr *a, byte *buf, uint size)
980
{
981
    u32 *labels = (u32 *) a->u.ptr->data;
982
    uint lnum = a->u.ptr->length / 4;
983
    char *pos = buf;
984

    
985
    for (uint i = 0; i < lnum; i++)
986
    {
987
        if (size < 20)
988
        {
989
            bsprintf(pos, "...");
990
            return;
991
        }
992

    
993
        uint l = bsprintf(pos, "%d/", labels[i]);
994
        ADVANCE(pos, size, l);
995
    }
996

    
997
    /* Clear last slash or terminate empty string */
998
    pos[lnum ? -1 : 0] = 0;
999
}
1000

    
1001
static inline void
1002
bgp_decode_unknown(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to)
1003
{
1004
    /* Cannot use bgp_set_attr_data() as it works on known attributes only */
1005
    ea_set_attr_data(to, s->pool, EA_CODE(EAP_BGP, code), flags, EAF_TYPE_OPAQUE, data, len);
1006
}
1007

    
1008

    
1009
/*
1010
 *        Attribute table
1011
 */
1012

    
1013
static const struct bgp_attr_desc bgp_attr_table[] = {
1014
        [BA_ORIGIN] = {
1015
                .name = "origin",
1016
                .type = EAF_TYPE_INT,
1017
                .flags = BAF_TRANSITIVE,
1018
                .export = bgp_export_origin,
1019
                .encode = bgp_encode_u8,
1020
                .decode = bgp_decode_origin,
1021
                .format = bgp_format_origin,
1022
        },
1023
        [BA_AS_PATH] = {
1024
                .name = "as_path",
1025
                .type = EAF_TYPE_AS_PATH,
1026
                .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1027
                .encode = bgp_encode_as_path,
1028
                .decode = bgp_decode_as_path,
1029
        },
1030
        [BA_AS_NH_LIST] = {
1031
                .name = "NH",
1032
                .type = EAF_TYPE_AS_PATH,
1033
                .flags = BAF_TRANSITIVE, //-> documentation
1034
                .encode = bgp_encode_nhs_list,
1035
                .decode = bgp_decode_nhs_list,
1036
        },
1037
        [BA_AS_LOAD] = {
1038
                .name = "AS_LOAD",
1039
                .type = EAF_TYPE_AS_PATH,
1040
                .flags = BAF_TRANSITIVE,
1041
                .encode = bgp_encode_as_load,
1042
                .decode = bgp_decode_as_load,
1043
        },
1044
        [BA_LOAD_OUT] = {
1045
                .name = "load_out",
1046
                .type = EAF_TYPE_INT,
1047
                .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1048
                .encode = bgp_encode_u32,
1049
                .decode = bgp_decode_load_out,
1050
        },
1051
        [BA_NEXT_HOP] = {
1052
                .name = "next_hop",
1053
                .type = EAF_TYPE_IP_ADDRESS,
1054
                .flags = BAF_TRANSITIVE,
1055
                .encode = bgp_encode_next_hop,
1056
                .decode = bgp_decode_next_hop,
1057
                .format = bgp_format_next_hop,
1058
        },
1059
        [BA_MULTI_EXIT_DISC] = {
1060
                .name = "med",
1061
                .type = EAF_TYPE_INT,
1062
                .flags = BAF_OPTIONAL,
1063
                .encode = bgp_encode_u32,
1064
                .decode = bgp_decode_med,
1065
        },
1066
        [BA_LOCAL_PREF] = {
1067
                .name = "local_pref",
1068
                .type = EAF_TYPE_INT,
1069
                .flags = BAF_TRANSITIVE,
1070
                .export = bgp_export_local_pref,
1071
                .encode = bgp_encode_u32,
1072
                .decode = bgp_decode_local_pref,
1073
        },
1074
        [BA_ATOMIC_AGGR] = {
1075
                .name = "atomic_aggr",
1076
                .type = EAF_TYPE_OPAQUE,
1077
                .flags = BAF_TRANSITIVE,
1078
                .encode = bgp_encode_raw,
1079
                .decode = bgp_decode_atomic_aggr,
1080
        },
1081
        [BA_AGGREGATOR] = {
1082
                .name = "aggregator",
1083
                .type = EAF_TYPE_OPAQUE,
1084
                .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1085
                .encode = bgp_encode_aggregator,
1086
                .decode = bgp_decode_aggregator,
1087
                .format = bgp_format_aggregator,
1088
        },
1089
        [BA_COMMUNITY] = {
1090
                .name = "community",
1091
                .type = EAF_TYPE_INT_SET,
1092
                .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1093
                .export = bgp_export_community,
1094
                .encode = bgp_encode_u32s,
1095
                .decode = bgp_decode_community,
1096
        },
1097
        [BA_ORIGINATOR_ID] = {
1098
                .name = "originator_id",
1099
                .type = EAF_TYPE_ROUTER_ID,
1100
                .flags = BAF_OPTIONAL,
1101
                .export = bgp_export_originator_id,
1102
                .encode = bgp_encode_u32,
1103
                .decode = bgp_decode_originator_id,
1104
        },
1105
        [BA_CLUSTER_LIST] = {
1106
                .name = "cluster_list",
1107
                .type = EAF_TYPE_INT_SET,
1108
                .flags = BAF_OPTIONAL,
1109
                .export = bgp_export_cluster_list,
1110
                .encode = bgp_encode_u32s,
1111
                .decode = bgp_decode_cluster_list,
1112
                .format = bgp_format_cluster_list,
1113
        },
1114
        [BA_MP_REACH_NLRI] = {
1115
                .name = "mp_reach_nlri",
1116
                .type = EAF_TYPE_OPAQUE,
1117
                .flags = BAF_OPTIONAL,
1118
                .decode = bgp_decode_mp_reach_nlri,
1119
        },
1120
        [BA_MP_UNREACH_NLRI] = {
1121
                .name = "mp_unreach_nlri",
1122
                .type = EAF_TYPE_OPAQUE,
1123
                .flags = BAF_OPTIONAL,
1124
                .decode = bgp_decode_mp_unreach_nlri,
1125
        },
1126
        [BA_EXT_COMMUNITY] = {
1127
                .name = "ext_community",
1128
                .type = EAF_TYPE_EC_SET,
1129
                .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1130
                .export = bgp_export_ext_community,
1131
                .encode = bgp_encode_u32s,
1132
                .decode = bgp_decode_ext_community,
1133
        },
1134
        [BA_AS4_PATH] = {
1135
                .name = "as4_path",
1136
                .type = EAF_TYPE_AS_PATH,
1137
                .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1138
                .encode = bgp_encode_raw,
1139
                .decode = bgp_decode_as4_path,
1140
        },
1141
        [BA_AS4_AGGREGATOR] = {
1142
                .name = "as4_aggregator",
1143
                .type = EAF_TYPE_OPAQUE,
1144
                .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1145
                .encode = bgp_encode_raw,
1146
                .decode = bgp_decode_as4_aggregator,
1147
                .format = bgp_format_aggregator,
1148
        },
1149
        [BA_LARGE_COMMUNITY] = {
1150
                .name = "large_community",
1151
                .type = EAF_TYPE_LC_SET,
1152
                .flags = BAF_OPTIONAL | BAF_TRANSITIVE,
1153
                .export = bgp_export_large_community,
1154
                .encode = bgp_encode_u32s,
1155
                .decode = bgp_decode_large_community,
1156
        },
1157
        [BA_MPLS_LABEL_STACK] = {
1158
                .name = "mpls_label_stack",
1159
                .type = EAF_TYPE_INT_SET,
1160
                .export = bgp_export_mpls_label_stack,
1161
                .encode = bgp_encode_mpls_label_stack,
1162
                .decode = bgp_decode_mpls_label_stack,
1163
                .format = bgp_format_mpls_label_stack,
1164
        },
1165
};
1166

    
1167
static inline int
1168
        bgp_attr_known(uint code)
1169
{
1170
return (code < ARRAY_SIZE(bgp_attr_table)) && bgp_attr_table[code].name;
1171
}
1172

    
1173

    
1174
/*
1175
 *        Attribute export
1176
 */
1177

    
1178
static inline void
1179
bgp_export_attr(struct bgp_export_state *s, eattr *a, ea_list *to)
1180
{
1181
    if (EA_PROTO(a->id) != EAP_BGP)
1182
        return;
1183

    
1184
    uint code = EA_ID(a->id);
1185

    
1186
    if (bgp_attr_known(code))
1187
    {
1188
        const struct bgp_attr_desc *desc = &bgp_attr_table[code];
1189

    
1190
        /* The flags might have been zero if the attr was added by filters */
1191
        a->flags = (a->flags & BAF_PARTIAL) | desc->flags;
1192

    
1193
        /* Set partial bit if new opt-trans attribute is attached to non-local route */
1194
        if ((s->src != NULL) && (a->type & EAF_ORIGINATED) &&
1195
            (a->flags & BAF_OPTIONAL) && (a->flags & BAF_TRANSITIVE))
1196
            a->flags |= BAF_PARTIAL;
1197

    
1198
        /* Call specific hook */
1199
        CALL(desc->export, s, a);
1200

    
1201
        /* Attribute might become undefined in hook */
1202
        if ((a->type & EAF_TYPE_MASK) == EAF_TYPE_UNDEF)
1203
            return;
1204
    }
1205
    else
1206
    {
1207
        /* Don't re-export unknown non-transitive attributes */
1208
        if (!(a->flags & BAF_TRANSITIVE))
1209
            return;
1210

    
1211
        a->flags |= BAF_PARTIAL;
1212
    }
1213

    
1214
    /* Append updated attribute */
1215
    to->attrs[to->count++] = *a;
1216
}
1217

    
1218
/**
1219
 * bgp_export_attrs - export BGP attributes
1220
 * @s: BGP export state
1221
 * @attrs: a list of extended attributes
1222
 *
1223
 * The bgp_export_attrs() function takes a list of attributes and merges it to
1224
 * one newly allocated and sorted segment. Attributes are validated and
1225
 * normalized by type-specific export hooks and attribute flags are updated.
1226
 * Some attributes may be eliminated (e.g. unknown non-tranitive attributes, or
1227
 * empty community sets).
1228
 *
1229
 * Result: one sorted attribute list segment, or NULL if attributes are unsuitable.
1230
 */
1231
static inline ea_list *
1232
bgp_export_attrs(struct bgp_export_state *s, ea_list *attrs)
1233
{
1234
    /* Merge the attribute list */
1235
    ea_list *new = lp_alloc(s->pool, ea_scan(attrs));
1236
    ea_merge(attrs, new);
1237
    ea_sort(new);
1238

    
1239
    uint i, count;
1240
    count = new->count;
1241
    new->count = 0;
1242

    
1243
    /* Export each attribute */
1244
    for (i = 0; i < count; i++)
1245
        bgp_export_attr(s, &new->attrs[i], new);
1246

    
1247
    if (s->err_withdraw)
1248
        return NULL;
1249

    
1250
    return new;
1251
}
1252

    
1253

    
1254
/*
1255
 *        Attribute encoding
1256
 */
1257

    
1258
static inline int
1259
bgp_encode_attr(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
1260
{
1261
    ASSERT(EA_PROTO(a->id) == EAP_BGP);
1262

    
1263
    uint code = EA_ID(a->id);
1264

    
1265
    if (bgp_attr_known(code))
1266
        return bgp_attr_table[code].encode(s, a, buf, size);
1267
    else
1268
        return bgp_encode_raw(s, a, buf, size);
1269
}
1270

    
1271
/**
1272
 * bgp_encode_attrs - encode BGP attributes
1273
 * @s: BGP write state
1274
 * @attrs: a list of extended attributes
1275
 * @buf: buffer
1276
 * @end: buffer end
1277
 *
1278
 * The bgp_encode_attrs() function takes a list of extended attributes
1279
 * and converts it to its BGP representation (a part of an Update message).
1280
 *
1281
 * Result: Length of the attribute block generated or -1 if not enough space.
1282
 */
1283
int
1284
bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end)
1285
{
1286
    byte *pos = buf;
1287
    int i, len;
1288

    
1289
    for (i = 0; i < attrs->count; i++)
1290
    {
1291
        len = bgp_encode_attr(s, &attrs->attrs[i], pos, end - pos);
1292

    
1293
        if (len < 0)
1294
            return -1;
1295

    
1296
        pos += len;
1297
    }
1298

    
1299
    return pos - buf;
1300
}
1301

    
1302

    
1303
/*
1304
 *        Attribute decoding
1305
 */
1306

    
1307
static void bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool);
1308

    
1309
/**
1310
 * Credo questa funzione rilevi un eventuale loop?
1311
 * @param p
1312
 * @param attrs
1313
 * @param asn
1314
 * @return
1315
 */
1316
static inline int
1317
bgp_as_path_loopy(struct bgp_proto *p, ea_list *attrs, u32 asn)
1318
{
1319
    eattr *e = bgp_find_attr(attrs, BA_AS_PATH);
1320
    int num = p->cf->allow_local_as + 1;
1321
    return (e && (num > 0) && as_path_contains(e->u.ptr, asn, num));
1322
}
1323

    
1324
static inline int
1325
bgp_originator_id_loopy(struct bgp_proto *p, ea_list *attrs)
1326
{
1327
    eattr *e = bgp_find_attr(attrs, BA_ORIGINATOR_ID);
1328
    return (e && (e->u.data == p->local_id));
1329
}
1330

    
1331
static inline int
1332
bgp_cluster_list_loopy(struct bgp_proto *p, ea_list *attrs)
1333
{
1334
    eattr *e = bgp_find_attr(attrs, BA_CLUSTER_LIST);
1335
    return (e && int_set_contains(e->u.ptr, p->rr_cluster_id));
1336
}
1337

    
1338
static inline void
1339
bgp_decode_attr(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to)
1340
{
1341
    /* Handle duplicate attributes; RFC 7606 3 (g) */
1342
    if (BIT32_TEST(s->attrs_seen, code))
1343
    {
1344
        if ((code == BA_MP_REACH_NLRI) || (code == BA_MP_UNREACH_NLRI))
1345
            bgp_parse_error(s, 1);
1346
        else
1347
            DISCARD("Discarding duplicate attribute (code %u)", code);
1348
    }
1349
    BIT32_SET(s->attrs_seen, code);
1350

    
1351
    if (bgp_attr_known(code))
1352
    {
1353
        const struct bgp_attr_desc *desc = &bgp_attr_table[code];
1354

    
1355
        /* Handle conflicting flags; RFC 7606 3 (c) */
1356
        if ((flags ^ desc->flags) & (BAF_OPTIONAL | BAF_TRANSITIVE))
1357
            WITHDRAW("Malformed %s attribute - conflicting flags (%02x)", desc->name, flags);
1358

    
1359
        //log(L_INFO "Richiedo la decodifica dell'atributo");
1360
        desc->decode(s, code, flags, data, len, to);
1361
    }
1362
    else /* Unknown attribute */
1363
    {
1364
        if (!(flags & BAF_OPTIONAL))
1365
            WITHDRAW("Unknown attribute (code %u) - conflicting flags (%02x)", code, flags);
1366

    
1367
        bgp_decode_unknown(s, code, flags, data, len, to);
1368
    }
1369
}
1370

    
1371
/**
1372
 * bgp_decode_attrs - check and decode BGP attributes
1373
 * @s: BGP parse state
1374
 * @data: start of attribute block
1375
 * @len: length of attribute block
1376
 *
1377
 * This function takes a BGP attribute block (a part of an Update message), checks
1378
 * its consistency and converts it to a list of BIRD route attributes represented
1379
 * by an (uncached) &rta.
1380
 */
1381
ea_list *
1382
bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len)
1383
{
1384
    //log(L_INFO "Decodifica attributo 1");
1385
    struct bgp_proto *p = s->proto;
1386
    ea_list *attrs = NULL;
1387
    uint code, flags, alen;
1388
    byte *pos = data;
1389

    
1390
    /* Parse the attributes */
1391
    while (len)
1392
    {
1393
        //log(L_INFO "Decodifica attributo 2");
1394
        alen = 0;
1395

    
1396
        /* Read attribute type */
1397
        if (len < 2)
1398
            goto framing_error;
1399
        flags = pos[0];
1400
        code = pos[1];
1401
        ADVANCE(pos, len, 2);
1402

    
1403
        /* Read attribute length */
1404
        if (flags & BAF_EXT_LEN)
1405
        {
1406
            if (len < 2)
1407
                goto framing_error;
1408
            alen = get_u16(pos);
1409
            ADVANCE(pos, len, 2);
1410
        }
1411
        else
1412
        {
1413
            if (len < 1)
1414
                goto framing_error;
1415
            alen = *pos;
1416
            ADVANCE(pos, len, 1);
1417
        }
1418

    
1419
        if (alen > len)
1420
            goto framing_error;
1421

    
1422
        DBG("Attr %02x %02x %u\n", code, flags, alen);
1423
        //log(L_INFO "Attr letto: %02x %02x %u", code, flags, alen);
1424
        bgp_decode_attr(s, code, flags, pos, alen, &attrs);
1425
        ADVANCE(pos, len, alen);
1426
    }
1427

    
1428
    if (s->err_withdraw) {
1429
        //log(L_INFO "Attivata decodifica con goto withdraw");
1430
        goto withdraw;
1431
    }
1432

    
1433
    /* If there is no reachability NLRI, we are finished */
1434
    if (!s->ip_reach_len && !s->mp_reach_len)
1435
        return NULL;
1436

    
1437

    
1438
    /* Handle missing mandatory attributes; RFC 7606 3 (d) */
1439
    if (!BIT32_TEST(s->attrs_seen, BA_ORIGIN))
1440
    { REPORT(NO_MANDATORY, "ORIGIN"); goto withdraw; }
1441

    
1442
    if (!BIT32_TEST(s->attrs_seen, BA_AS_PATH))
1443
    { REPORT(NO_MANDATORY, "AS_PATH"); goto withdraw; }
1444

    
1445
    /* When receiving attributes from non-AS4-aware BGP speaker, we have to
1446
       reconstruct AS_PATH and AGGREGATOR attributes; RFC 6793 4.2.3 */
1447
    if (!p->as4_session)
1448
        bgp_process_as4_attrs(&attrs, s->pool);
1449

    
1450
    /* Reject routes with our ASN in AS_PATH attribute */
1451
    if (bgp_as_path_loopy(p, attrs, p->local_as)) {
1452
        //log(L_INFO "HEI HO SCOPERTO CHE C'È UN LOOP!");
1453
        rilevatoLoop = 1;
1454
        goto withdraw;
1455
    }
1456

    
1457
    /* Reject routes with our Confederation ID in AS_PATH attribute; RFC 5065 4.0 */
1458
    if ((p->public_as != p->local_as) && bgp_as_path_loopy(p, attrs, p->public_as))
1459
        goto withdraw;
1460

    
1461
    /* Reject routes with our Router ID in ORIGINATOR_ID attribute; RFC 4456 8 */
1462
    if (p->is_internal && bgp_originator_id_loopy(p, attrs))
1463
        goto withdraw;
1464

    
1465
    /* Reject routes with our Cluster ID in CLUSTER_LIST attribute; RFC 4456 8 */
1466
    if (p->rr_client && bgp_cluster_list_loopy(p, attrs))
1467
        goto withdraw;
1468

    
1469
    /* If there is no local preference, define one */
1470
    if (!BIT32_TEST(s->attrs_seen, BA_LOCAL_PREF))
1471
        bgp_set_attr_u32(&attrs, s->pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref);
1472

    
1473
    return attrs;
1474

    
1475

    
1476
    framing_error:
1477
    /* RFC 7606 4 - handle attribute framing errors */
1478
    REPORT("Malformed attribute list - framing error (%u/%u) at %d",
1479
           alen, len, (int) (pos - s->attrs));
1480

    
1481
    withdraw:
1482
    //log(L_INFO "Decodifica attributo 3");
1483
    /* RFC 7606 5.2 - handle missing NLRI during errors */
1484
    if (!s->ip_reach_len && !s->mp_reach_len)
1485
        bgp_parse_error(s, 1);
1486

    
1487
    //log(L_INFO "Decodifica attributo 4");
1488
    s->err_withdraw = 1;
1489
    return NULL;
1490
}
1491

    
1492

    
1493
/*
1494
 *        Route bucket hash table
1495
 */
1496

    
1497
#define RBH_KEY(b)                b->eattrs, b->hash
1498
#define RBH_NEXT(b)                b->next
1499
#define RBH_EQ(a1,h1,a2,h2)        h1 == h2 && ea_same(a1, a2)
1500
#define RBH_FN(a,h)                h
1501

    
1502
#define RBH_REHASH                bgp_rbh_rehash
1503
#define RBH_PARAMS                /8, *2, 2, 2, 8, 20
1504

    
1505

    
1506
HASH_DEFINE_REHASH_FN(RBH, struct bgp_bucket)
1507

    
1508
void
1509
bgp_init_bucket_table(struct bgp_channel *c)
1510
{
1511
    HASH_INIT(c->bucket_hash, c->pool, 8);
1512

    
1513
    init_list(&c->bucket_queue);
1514
    c->withdraw_bucket = NULL;
1515
}
1516

    
1517
void
1518
bgp_free_bucket_table(struct bgp_channel *c)
1519
{
1520
    HASH_FREE(c->bucket_hash);
1521

    
1522
    struct bgp_bucket *b;
1523
    WALK_LIST_FIRST(b, c->bucket_queue)
1524
    {
1525
        rem_node(&b->send_node);
1526
        mb_free(b);
1527
    }
1528

    
1529
    mb_free(c->withdraw_bucket);
1530
    c->withdraw_bucket = NULL;
1531
}
1532

    
1533
struct bgp_bucket *
1534
bgp_get_bucket(struct bgp_channel *c, ea_list *new)
1535
{
1536
    /* Hash and lookup */
1537
    u32 hash = ea_hash(new);
1538
    struct bgp_bucket *b = HASH_FIND(c->bucket_hash, RBH, new, hash);
1539

    
1540
    if (b)
1541
    return b;
1542

    
1543
    uint ea_size = sizeof(ea_list) + new->count * sizeof(eattr);
1544
    uint ea_size_aligned = BIRD_ALIGN(ea_size, CPU_STRUCT_ALIGN);
1545
    uint size = sizeof(struct bgp_bucket) + ea_size_aligned;
1546
    uint i;
1547
    byte *dest;
1548

    
1549
    /* Gather total size of non-inline attributes */
1550
    for (i = 0; i < new->count; i++)
1551
    {
1552
        eattr *a = &new->attrs[i];
1553

    
1554
        if (!(a->type & EAF_EMBEDDED))
1555
            size += BIRD_ALIGN(sizeof(struct adata) + a->u.ptr->length, CPU_STRUCT_ALIGN);
1556
    }
1557

    
1558
    /* Create the bucket */
1559
    b = mb_alloc(c->pool, size);
1560
    init_list(&b->prefixes);
1561
    b->hash = hash;
1562

    
1563
    /* Copy list of extended attributes */
1564
    memcpy(b->eattrs, new, ea_size);
1565
    dest = ((byte *) b->eattrs) + ea_size_aligned;
1566

    
1567
    /* Copy values of non-inline attributes */
1568
    for (i = 0; i < new->count; i++)
1569
    {
1570
        eattr *a = &b->eattrs->attrs[i];
1571

    
1572
        if (!(a->type & EAF_EMBEDDED))
1573
        {
1574
            struct adata *oa = a->u.ptr;
1575
            struct adata *na = (struct adata *) dest;
1576
            memcpy(na, oa, sizeof(struct adata) + oa->length);
1577
            a->u.ptr = na;
1578
            dest += BIRD_ALIGN(sizeof(struct adata) + na->length, CPU_STRUCT_ALIGN);
1579
        }
1580
    }
1581

    
1582
    /* Insert the bucket to send queue and bucket hash */
1583
    add_tail(&c->bucket_queue, &b->send_node);
1584
    HASH_INSERT2(c->bucket_hash, RBH, c->pool, b);
1585

    
1586
    return b;
1587
}
1588

    
1589
static struct bgp_bucket *
1590
bgp_get_withdraw_bucket(struct bgp_channel *c)
1591
{
1592
    if (!c->withdraw_bucket)
1593
    {
1594
        c->withdraw_bucket = mb_allocz(c->pool, sizeof(struct bgp_bucket));
1595
        init_list(&c->withdraw_bucket->prefixes);
1596
    }
1597

    
1598
    return c->withdraw_bucket;
1599
}
1600

    
1601
void
1602
bgp_free_bucket(struct bgp_channel *c, struct bgp_bucket *b)
1603
{
1604
    rem_node(&b->send_node);
1605
    HASH_REMOVE2(c->bucket_hash, RBH, c->pool, b);
1606
    mb_free(b);
1607
}
1608

    
1609
void
1610
bgp_defer_bucket(struct bgp_channel *c, struct bgp_bucket *b)
1611
{
1612
    rem_node(&b->send_node);
1613
    add_tail(&c->bucket_queue, &b->send_node);
1614
}
1615

    
1616
void
1617
bgp_withdraw_bucket(struct bgp_channel *c, struct bgp_bucket *b)
1618
{
1619
    struct bgp_proto *p = (void *) c->c.proto;
1620
    struct bgp_bucket *wb = bgp_get_withdraw_bucket(c);
1621

    
1622
    log(L_ERR "%s: Attribute list too long", p->p.name);
1623
    while (!EMPTY_LIST(b->prefixes))
1624
    {
1625
        struct bgp_prefix *px = HEAD(b->prefixes);
1626

    
1627
        log(L_ERR "%s: - withdrawing %N", p->p.name, &px->net);
1628
        rem_node(&px->buck_node);
1629
        add_tail(&wb->prefixes, &px->buck_node);
1630
    }
1631
}
1632

    
1633

    
1634
/*
1635
 *        Prefix hash table
1636
 */
1637

    
1638
#define PXH_KEY(px)                px->net, px->path_id, px->hash
1639
#define PXH_NEXT(px)                px->next
1640
//I have no idea of what I'm reading in the line below
1641
#define PXH_EQ(n1,i1,h1,n2,i2,h2) h1 == h2 && i1 == i2 && net_equal(n1, n2)
1642
#define PXH_FN(n,i,h)                h
1643

    
1644
#define PXH_REHASH                bgp_pxh_rehash
1645
#define PXH_PARAMS                /8, *2, 2, 2, 8, 20
1646

    
1647

    
1648
HASH_DEFINE_REHASH_FN(PXH, struct bgp_prefix)
1649

    
1650
void
1651
bgp_init_prefix_table(struct bgp_channel *c)
1652
{
1653
    HASH_INIT(c->prefix_hash, c->pool, 8);
1654

    
1655
    uint alen = net_addr_length[c->c.net_type];
1656
    c->prefix_slab = alen ? sl_new(c->pool, sizeof(struct bgp_prefix) + alen) : NULL;
1657
}
1658

    
1659
void
1660
bgp_free_prefix_table(struct bgp_channel *c)
1661
{
1662
    HASH_FREE(c->prefix_hash);
1663

    
1664
    rfree(c->prefix_slab);
1665
    c->prefix_slab = NULL;
1666
}
1667

    
1668
struct bgp_prefix *
1669
bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
1670
{
1671
    u32 hash = net_hash(net) ^ u32_hash(path_id);
1672
    struct bgp_prefix *px = HASH_FIND(c->prefix_hash, PXH, net, path_id, hash);
1673
    if (px)
1674
    {
1675
        rem_node(&px->buck_node);
1676
        return px;
1677
    }
1678

    
1679
    if (c->prefix_slab)
1680
        px = sl_alloc(c->prefix_slab);
1681
    else
1682
        px = mb_alloc(c->pool, sizeof(struct bgp_prefix) + net->length);
1683
    px->buck_node.next = NULL;
1684
    px->buck_node.prev = NULL;
1685
    px->hash = hash;
1686
    px->path_id = path_id;
1687
    net_copy(px->net, net);
1688
    HASH_INSERT2(c->prefix_hash, PXH, c->pool, px);
1689
    return px;
1690
}
1691

    
1692
void
1693
bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *px)
1694
{
1695
    rem_node(&px->buck_node);
1696
    HASH_REMOVE2(c->prefix_hash, PXH, c->pool, px);
1697

    
1698
    if (c->prefix_slab)
1699
        sl_free(c->prefix_slab, px);
1700
    else
1701
        mb_free(px);
1702
}
1703

    
1704

    
1705
/*
1706
 *        BGP protocol glue -> wtf is a protocol glue?
1707
 *        and nice tab use
1708
 */
1709

    
1710
int
1711
bgp_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
1712
{
1713
rte *e = *new;
1714
struct proto *SRC = e->attrs->src->proto;
1715
struct bgp_proto *p = (struct bgp_proto *) P;
1716
struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (struct bgp_proto *) SRC : NULL;
1717

    
1718
//TODO prima era return 0
1719
/* Reject our routes */
1720
if (src == p){
1721
    //log(L_INFO "WITHDRAW CHECKER = %d", withdraw_checker);
1722
    return 0;
1723
}
1724

    
1725
/* Accept non-BGP routes */
1726
if (src == NULL)
1727
return 0;
1728

    
1729
// XXXX: Check next hop AF
1730

    
1731
/* IBGP route reflection, RFC 4456 */
1732
if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
1733
{
1734
/* Rejected unless configured as route reflector */
1735
if (!p->rr_client && !src->rr_client)
1736
return -1;
1737

    
1738
/* Generally, this should be handled when path is received, but we check it
1739
   also here as rr_cluster_id may be undefined or different in src. */
1740
if (p->rr_cluster_id && bgp_cluster_list_loopy(p, e->attrs->eattrs))
1741
return -1;
1742
}
1743

    
1744
/* Handle well-known communities, RFC 1997 */
1745
struct eattr *c;
1746
if (p->cf->interpret_communities &&
1747
(c = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_COMMUNITY))))
1748
{
1749
struct adata *d = c->u.ptr;
1750

    
1751
/* Do not export anywhere */
1752
if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
1753
return -1;
1754

    
1755
/* Do not export outside of AS (or member-AS) */
1756
if (!p->is_internal && int_set_contains(d, BGP_COMM_NO_EXPORT_SUBCONFED))
1757
return -1;
1758

    
1759
/* Do not export outside of AS (or confederation) */
1760
if (!p->is_interior && int_set_contains(d, BGP_COMM_NO_EXPORT))
1761
return -1;
1762
}
1763

    
1764
return 0;
1765
}
1766

    
1767

    
1768
static adata null_adata;        /* adata of length 0 */
1769

    
1770
//TODO refactor the code below, done one time, redo it with the thing in the protocol
1771
ea_list *
1772
bgp_update_attrs(struct bgp_proto *p, struct bgp_channel *c, rte *e, ea_list *attrs0, struct linpool *pool)
1773
{
1774
    struct proto *SRC = e->attrs->src->proto;
1775
    struct bgp_proto *src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
1776
    struct bgp_export_state s = { .proto = p, .channel = c, .pool = pool, .src = src, .route = e, .mpls = c->desc->mpls };
1777
    ea_list *attrs = attrs0;
1778
    eattr *a;
1779
    adata *ad;
1780
    char bufProto[16] = "";
1781
    map_iter_t iter;
1782

    
1783
    RTable *objForDestination = map_get(&RTmap, cKey);
1784
    const char *key;
1785

    
1786
    /* ORIGIN attribute - mandatory, attach if missing */
1787
    if (! bgp_find_attr(attrs0, BA_ORIGIN))
1788
        bgp_set_attr_u32(&attrs, pool, BA_ORIGIN, 0, src ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
1789

    
1790
    if(withdraw_checker == 0) {
1791
        int integerLoadOut = *((int *) &loadOut);
1792
        bgp_set_attr_u32(&attrs, pool, BA_LOAD_OUT, 0, integerLoadOut);
1793
    }
1794

    
1795
    /* AS_PATH attribute - mandatory */
1796
    a = bgp_find_attr(attrs0, BA_AS_PATH);
1797
    ad = a ? a->u.ptr : &null_adata;
1798

    
1799
    /* AS_PATH attribute - strip AS_CONFED* segments outside confederation */
1800
    if ((!p->cf->confederation || !p->is_interior) && as_path_contains_confed(ad)) {
1801
        ad = as_path_strip_confed(pool, ad);
1802
    }
1803

    
1804
    /* AS_PATH attribute - keep or prepend ASN */
1805
    if (p->is_internal ||
1806
        (p->rs_client && src && src->rs_client))
1807
    {
1808
        /* IBGP or route server -> just ensure there is one */
1809
        if (!a)
1810
            bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, &null_adata);
1811
    }
1812
    else if (p->is_interior)
1813
    {
1814
        /* Confederation -> prepend ASN as AS_CONFED_SEQUENCE */
1815
        ad = as_path_prepend2(pool, ad, AS_PATH_CONFED_SEQUENCE, p->public_as);
1816
        bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, ad);
1817
    }
1818
    else /* Regular EBGP (no RS, no confederation) */
1819
    {
1820
        /* Regular EBGP -> prepend ASN as regular sequence */
1821
        ad = as_path_prepend2(pool, ad, AS_PATH_SEQUENCE, p->public_as);
1822
        bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, ad);
1823

    
1824
        //All data is loaded in the nexthope data structure and load data structure
1825
        if(withdraw_checker == 0 && objForDestination != NULL) {
1826

    
1827
            /* set the nh_list attribute */
1828
            adata *nh_list = &null_adata; //Clean the attribute received
1829
            iter = map_iter(&objForDestination->NH);
1830
            while ((key = map_next(&objForDestination->NH, &iter))) {
1831
                int *value = map_get(&objForDestination->NH, key);
1832
                value ? nh_list = as_path_prepend2(pool, nh_list, AS_PATH_SEQUENCE, *value)
1833
                        : log(L_INFO "ERROR, nh value NULL");
1834
            }
1835
            bgp_set_attr_ptr(&attrs, pool, BA_AS_NH_LIST, 0, nh_list);
1836

    
1837
            /* Set the as know list */
1838
            adata *as_data_list = &null_adata;
1839
            iter = map_iter(&ASLoad_map);
1840

    
1841
            sprintf(bufProto, "%d", p->public_as);
1842
            ASLoad *ASLoad_element = map_get(&ASLoad_map, bufProto);
1843
            if (ASLoad_element) {
1844
                //Local AS Load element already exists
1845
                if (ASLoad_element->load != loadComplessivo) {
1846
                    // Update the actual value
1847
                    ASLoad_element->load = loadComplessivo;
1848
                    ASLoad_element->metrica += 1;
1849

    
1850
                    while ((key = map_next(&ASLoad_element->remoteMap, &iter))) {
1851
                        map_remove(&ASLoad_element->remoteMap, key);
1852
                    }
1853
                }
1854
            } else {
1855
                //Create the local load element
1856
                ASLoad new_ASLoad = {loadComplessivo, 1, 1, NULL};
1857
                map_init(&new_ASLoad.remoteMap);
1858
                map_set(&ASLoad_map, bufProto, new_ASLoad);
1859
            }
1860

    
1861
            /* Set values in the list */
1862
            while ((key = map_next(&ASLoad_map, &iter))) {
1863

    
1864
                ASLoad *ASLoad_element = map_get(&ASLoad_map, key);
1865
                sprintf(bufProto, "%u", p->remote_id);
1866

    
1867
                if(ASLoad_element != NULL && !map_get(&ASLoad_element->remoteMap, bufProto)) {
1868
                    int ASValue = (int) strtol(key, (char **) NULL, 10);
1869
                    //log(L_INFO "AS che voglio inviare: %d", ASValue);
1870
                    int integerASLoad = *((int *) &(ASLoad_element->load));
1871
                    as_data_list = as_path_prepend2(pool, as_data_list, AS_PATH_SEQUENCE, ASLoad_element->metrica);
1872
                    as_data_list = as_path_prepend2(pool, as_data_list, AS_PATH_SEQUENCE, integerASLoad);
1873
                    as_data_list = as_path_prepend2(pool, as_data_list, AS_PATH_SEQUENCE, ASValue);
1874

    
1875
                    remoteAS remote = {p->remote_id};
1876
                    if(map_set(&ASLoad_element->remoteMap, bufProto, remote) != 0){
1877
                        log(L_INFO "NON ggiunto correttamente %u", remote.remote_as);
1878
                    }
1879
                }
1880
            }
1881

    
1882
            bgp_set_attr_ptr(&attrs, pool, BA_AS_LOAD, 0, as_data_list);
1883
        }
1884

    
1885
        /* MULTI_EXIT_DESC attribute - accept only if set in export filter */
1886
        a = bgp_find_attr(attrs0, BA_MULTI_EXIT_DISC);
1887
        if (a && !(a->type & EAF_FRESH))
1888
            bgp_unset_attr(&attrs, pool, BA_MULTI_EXIT_DISC);
1889
    }
1890

    
1891
    /* NEXT_HOP attribute - delegated to AF-specific hook */
1892
    a = bgp_find_attr(attrs0, BA_NEXT_HOP);
1893
    bgp_update_next_hop(&s, a, &attrs);
1894

    
1895
    /* LOCAL_PREF attribute - required for IBGP, attach if missing */
1896
    if (p->is_interior && ! bgp_find_attr(attrs0, BA_LOCAL_PREF))
1897
        bgp_set_attr_u32(&attrs, pool, BA_LOCAL_PREF, 0, p->cf->default_local_pref);
1898

    
1899
    /* IBGP route reflection, RFC 4456 */
1900
    if (src && src->is_internal && p->is_internal && (src->local_as == p->local_as))
1901
    {
1902
        /* ORIGINATOR_ID attribute - attach if not already set */
1903
        if (! bgp_find_attr(attrs0, BA_ORIGINATOR_ID))
1904
            bgp_set_attr_u32(&attrs, pool, BA_ORIGINATOR_ID, 0, src->remote_id);
1905

    
1906
        /* CLUSTER_LIST attribute - prepend cluster ID */
1907
        a = bgp_find_attr(attrs0, BA_CLUSTER_LIST);
1908
        ad = a ? a->u.ptr : NULL;
1909

    
1910
        /* Prepend src cluster ID */
1911
        if (src->rr_cluster_id)
1912
            ad = int_set_prepend(pool, ad, src->rr_cluster_id);
1913

    
1914
        /* Prepend dst cluster ID if src and dst clusters are different */
1915
        if (p->rr_cluster_id && (src->rr_cluster_id != p->rr_cluster_id))
1916
            ad = int_set_prepend(pool, ad, p->rr_cluster_id);
1917

    
1918
        /* Should be at least one prepended cluster ID */
1919
        bgp_set_attr_ptr(&attrs, pool, BA_CLUSTER_LIST, 0, ad);
1920
    }
1921

    
1922
    /* AS4_* transition attributes, RFC 6793 4.2.2 */
1923
    if (! p->as4_session)
1924
    {
1925
        a = bgp_find_attr(attrs, BA_AS_PATH);
1926
        if (a && as_path_contains_as4(a->u.ptr))
1927
        {
1928
            bgp_set_attr_ptr(&attrs, pool, BA_AS_PATH, 0, as_path_to_old(pool, a->u.ptr));
1929
            bgp_set_attr_ptr(&attrs, pool, BA_AS4_PATH, 0, as_path_strip_confed(pool, a->u.ptr));
1930
        }
1931

    
1932
        a = bgp_find_attr(attrs, BA_AGGREGATOR);
1933
        if (a && aggregator_contains_as4(a->u.ptr))
1934
        {
1935
            bgp_set_attr_ptr(&attrs, pool, BA_AGGREGATOR, 0, aggregator_to_old(pool, a->u.ptr));
1936
            bgp_set_attr_ptr(&attrs, pool, BA_AS4_AGGREGATOR, 0, a->u.ptr);
1937
        }
1938
    }
1939

    
1940
    /*
1941
     * Presence of mandatory attributes ORIGIN and AS_PATH is ensured by above
1942
     * conditions. Presence and validity of quasi-mandatory NEXT_HOP attribute
1943
     * should be checked in AF-specific hooks.
1944
     */
1945

    
1946
    /* Apply per-attribute export hooks for validatation and normalization */
1947
    withdraw_checker = 0;
1948
    return bgp_export_attrs(&s, attrs);
1949
}
1950

    
1951
//TODO refactor the code below, first round of refactoring done
1952
void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old, ea_list *attrs)
1953
{
1954
    struct bgp_proto *p = (void *) P;
1955
    struct bgp_channel *c = (void *) C;
1956
    struct bgp_bucket *buck;
1957
    struct bgp_prefix *px;
1958
    u32 path;
1959
    const char *key;
1960
    map_iter_t iterator;
1961

    
1962
    //The key is composed by the summ of the four part of the address
1963
    sprintf(cKey, "%d", n->n.addr->data[0] + n->n.addr->data[1] + n->n.addr->data[2] + n->n.addr->data[3]);
1964
    if(withdraw_checker == 0){
1965
        if (! bgp_find_attr(attrs, BA_ORIGIN)){
1966
            eattr *a = bgp_find_attr(attrs,BA_ORIGIN);
1967
            RTable *rt = map_get(&RTmap, cKey);
1968

    
1969
            if (!rt) {
1970
                struct bgp_proto *src;
1971
                if(new != NULL){
1972
                    struct proto *SRC = new->attrs->src->proto;
1973
                    src = (SRC->proto == &proto_bgp) ? (void *) SRC : NULL;
1974
                } else {
1975
                    src = NULL;
1976
                }
1977

    
1978
                if(!src){
1979
                    esportoDestinazioni = 1; // Internal origin
1980
                    RTable rtElem = initRTableElement(n->n.addr,0,0);
1981

    
1982
                    if(map_get(&ExternalDestinationMap,cKey) == NULL){
1983
                        if(map_set(&RTmap, &cKey[0], rtElem) != 0){
1984
                            log(L_INFO "Elemento non aggiunto alla mappa");
1985
                        }
1986
                    }
1987
                }
1988
            }
1989
        }
1990
    }
1991

    
1992
    if (new)
1993
    {
1994
        RTable *objForDestination = map_get(&RTmap, cKey);
1995
        if (objForDestination) {
1996
            if(esportoDestinazioni == 1){
1997
                loadOut = 1;    //Destination node
1998
            } else {
1999
                loadOut = 0;    //Transit node
2000
            }
2001
            iterator = map_iter(&objForDestination->NH);
2002
            int i = 0;
2003
            while ((key = map_next(&objForDestination->NH, &iterator))) {
2004
                i++;    //Count how much NH are in the table for this destination
2005
            }
2006
            if(i==0 && objForDestination->interno == 1){   //If there is no NH and the origin is internal
2007
                map_remove(&RTmap, cKey);
2008
            } else {
2009
                iterator = map_iter(&objForDestination->loadin);
2010
                while (key = map_next(&objForDestination->loadin, &iterator)) {
2011
                    float *value = map_get(&objForDestination->loadin, key);
2012
                    if(value != NULL){
2013
                        loadOut += *value;
2014
                    }
2015
                }
2016
            }
2017
        }
2018

    
2019
        attrs = bgp_update_attrs(p, c, new, attrs, bgp_linpool2);
2020

    
2021
        /* If attributes are invalid, we fail back to withdraw */
2022
        buck = attrs ? bgp_get_bucket(c, attrs) : bgp_get_withdraw_bucket(c);
2023
        path = new->attrs->src->global_id;
2024
        lp_flush(bgp_linpool2);
2025
    }
2026
    else
2027
    {
2028
        buck = bgp_get_withdraw_bucket(c);
2029
        path = old->attrs->src->global_id;
2030
    }
2031
    px = bgp_get_prefix(c, n->n.addr, c->add_path_tx ? path : 0);
2032
    add_tail(&buck->prefixes, &px->buck_node);
2033

    
2034
    if(p->conn != NULL && C != NULL) {
2035
        bgp_schedule_packet(p->conn, c, PKT_UPDATE);
2036
    }
2037
    /* Simil MRAI variant
2038
    if(tm_remains(p->conn->mrai_timer) == 0){
2039
        if(p->conn != NULL && C == NULL) {
2040
            bgp_schedule_packet(p->conn, c, PKT_UPDATE);
2041
        }
2042
        bgp_start_timer(p->conn->mrai_timer, 5);
2043
    } */
2044
}
2045

    
2046
static inline u32
2047
bgp_get_neighbor(rte *r)
2048
{
2049
    eattr *e = ea_find(r->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
2050
    u32 as;
2051

    
2052
    if (e && as_path_get_first_regular(e->u.ptr, &as))
2053
        return as;
2054

    
2055
    /* If AS_PATH is not defined, we treat rte as locally originated */
2056
    struct bgp_proto *p = (void *) r->attrs->src->proto;
2057
    return p->cf->confederation ?: p->local_as;
2058
}
2059

    
2060
static inline int
2061
rte_resolvable(rte *rt)
2062
{
2063
    return rt->attrs->dest == RTD_UNICAST;
2064
}
2065

    
2066
//TODO refactoring, first refactoring done
2067
/**
2068
 * Function to update the NH of an already known route
2069
 * @param aggiungoNH
2070
 */
2071
void updateNHmap(int aggiungoNH){
2072
    RTable *objFound = map_get(&RTmap, cKey);
2073
    const char *keyTmp;
2074
    map_iter_t iterator;
2075

    
2076
    if(aggiungoNH == 0){
2077
        // viene mantenuta la rotta vecchia che sarà anche NH, rimuovo questo NH
2078
        if(withdraw_checker == 1)
2079
            return;
2080
        if(NhVecchio == 0 && objFound != NULL)
2081
            map_remove(&objFound->NH, nhCKey);
2082
    } else {
2083
        // viene mantenuta la rotta nuova che sarà anche NH, rimuovo tutti i NH che non sono la rotta nuova
2084
        if(withdraw_checker == 1)
2085
            return;
2086
        if(objFound != NULL) {
2087
            iterator = map_iter(&objFound->NH);
2088
            while ((keyTmp = map_next(&objFound->NH, &iterator))) {
2089
                if (strcmp(&nhCKey[0], keyTmp))
2090
                    map_remove(&objFound->NH, keyTmp);
2091
            }
2092
            if (map_get(&objFound->NH,nhCKey) == NULL)
2093
                map_set(&objFound->NH,nhCKey,ASRicezione);
2094
        }
2095
        objFound->primaVolta = 1;
2096
    }
2097

    
2098
    if(objFound != NULL) {
2099
        int i = 0;
2100
        map_iter_t iterator = map_iter(&objFound->NH);
2101
        while ((keyTmp = map_next(&objFound->NH, &iterator))) {
2102
            i++;
2103
        }
2104
        if (i == 0) {
2105
            //If there is no more NH for the route i remove it from the data structure
2106
            map_remove(&RTmap, cKey);
2107
        }
2108
    }
2109
}
2110

    
2111
/**
2112
 * Function to mantain the new or the old, called after a collision on the routing table
2113
 * @param new
2114
 * @param old
2115
 * @return
2116
 */
2117
int
2118
bgp_rte_better(rte *new, rte *old)
2119
{
2120
    int key = 0;
2121
    key = new->net->n.addr->data[0] + new->net->n.addr->data[1] + new->net->n.addr->data[2] + new->net->n.addr->data[3];
2122
    sprintf(cKey, "%d", key);
2123
    sprintf(nhCKey, "%d", nhKey);
2124

    
2125
    struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->src->proto;
2126
    struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->src->proto;
2127
    eattr *x, *y;
2128
    u32 n, o;
2129

    
2130
    /* Skip suppressed routes (see bgp_rte_recalculate()) */
2131
    n = new->u.bgp.suppressed;
2132
    o = old->u.bgp.suppressed;
2133
    if (n > o){
2134
        updateNHmap(0);
2135
        return 0;
2136
    }
2137
    if (n < o){
2138
        updateNHmap(1);
2139
        return 1;
2140
    }
2141

    
2142
    /* RFC 4271 9.1.2.1. Route resolvability test */
2143
    n = rte_resolvable(new);
2144
    o = rte_resolvable(old);
2145
    if (n > o){
2146
        updateNHmap(1);
2147
        return 1;
2148
    }
2149
    if (n < o){
2150
        updateNHmap(0);
2151
        return 0;
2152
    }
2153

    
2154
    /* Start with local preferences */
2155
    x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
2156
    y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
2157
    n = x ? x->u.data : new_bgp->cf->default_local_pref;
2158
    o = y ? y->u.data : old_bgp->cf->default_local_pref;
2159
    if (n > o){
2160
        updateNHmap(1);
2161
        return 1;
2162
    }
2163
    if (n < o){
2164
        updateNHmap(0);
2165
        return 0;
2166
    }
2167

    
2168
    /* RFC 4271 9.1.2.2. a)  Use AS path lengths */
2169
    if (new_bgp->cf->compare_path_lengths || old_bgp->cf->compare_path_lengths)
2170
    {
2171
        x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
2172
        y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
2173
        n = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
2174
        o = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
2175
        if (n < o){
2176
            updateNHmap(1);
2177
            return 1;
2178
        }
2179
        if (n > o){
2180
            updateNHmap(0);
2181
            return 0;
2182
        }
2183
    }
2184

    
2185
    /* RFC 4271 9.1.2.2. b) Use origins */
2186
    x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN));
2187
    y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN));
2188
    n = x ? x->u.data : ORIGIN_INCOMPLETE;
2189
    o = y ? y->u.data : ORIGIN_INCOMPLETE;
2190
    if (n < o){
2191
        updateNHmap(1);
2192
        return 1;
2193
    }
2194
    if (n > o){
2195
        updateNHmap(0);
2196
        return 0;
2197
    }
2198

    
2199
    /* RFC 4271 9.1.2.2. c) Compare MED's */
2200
    /* Proper RFC 4271 path selection cannot be interpreted as finding
2201
     * the best path in some ordering. It is implemented partially in
2202
     * bgp_rte_recalculate() when deterministic_med option is
2203
     * active. Without that option, the behavior is just an
2204
     * approximation, which in specific situations may lead to
2205
     * persistent routing loops, because it is nondeterministic - it
2206
     * depends on the order in which routes appeared. But it is also the
2207
     * same behavior as used by default in Cisco routers, so it is
2208
     * probably not a big issue.
2209
     */
2210
    if (new_bgp->cf->med_metric || old_bgp->cf->med_metric ||
2211
        (bgp_get_neighbor(new) == bgp_get_neighbor(old)))
2212
    {
2213
        x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
2214
        y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
2215
        n = x ? x->u.data : new_bgp->cf->default_med;
2216
        o = y ? y->u.data : old_bgp->cf->default_med;
2217
        if (n < o){
2218
            updateNHmap(1);
2219
            return 1;
2220
        }
2221
        if (n > o){
2222
            updateNHmap(0);
2223
            return 0;
2224
        }
2225
    }
2226

    
2227
    /* RFC 4271 9.1.2.2. d) Prefer external peers */
2228
    if (new_bgp->is_interior > old_bgp->is_interior){
2229
        updateNHmap(0);
2230
        return 0;
2231
    }
2232
    if (new_bgp->is_interior < old_bgp->is_interior){
2233
        updateNHmap(1);
2234
        return 1;
2235
    }
2236

    
2237
    /* RFC 4271 9.1.2.2. e) Compare IGP metrics */
2238
    n = new_bgp->cf->igp_metric ? new->attrs->igp_metric : 0;
2239
    o = old_bgp->cf->igp_metric ? old->attrs->igp_metric : 0;
2240
    if (n < o)
2241
        return 1;
2242
    if (n > o)
2243
        return 0;
2244

    
2245
    /* RFC 4271 9.1.2.2. f) Compare BGP identifiers */
2246
    /* RFC 4456 9. a) Use ORIGINATOR_ID instead of local neighbor ID */
2247
    x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
2248
    y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
2249
    n = x ? x->u.data : new_bgp->remote_id;
2250
    o = y ? y->u.data : old_bgp->remote_id;
2251

    
2252
    /* RFC 5004 - prefer older routes */
2253
    /* (if both are external and from different peer) */
2254
    if ((new_bgp->cf->prefer_older || old_bgp->cf->prefer_older) &&
2255
        !new_bgp->is_internal && n != o){
2256
        updateNHmap(0);
2257
        return 0;
2258
    }
2259

    
2260
    /* rest of RFC 4271 9.1.2.2. f) */
2261
    if (n < o){
2262
        updateNHmap(1);
2263
        return 1;
2264
    }
2265
    if (n > o){
2266
        updateNHmap(0);
2267
        return 0;
2268
    }
2269

    
2270
    /* RFC 4456 9. b) Compare cluster list lengths */
2271
    x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST));
2272
    y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_CLUSTER_LIST));
2273
    n = x ? int_set_get_size(x->u.ptr) : 0;
2274
    o = y ? int_set_get_size(y->u.ptr) : 0;
2275
    if (n < o){
2276
        updateNHmap(1);
2277
        return 1;
2278
    }
2279
    if (n > o){
2280
        updateNHmap(0);
2281
        return 0;
2282
    }
2283

    
2284
    /* RFC 4271 9.1.2.2. g) Compare peer IP adresses */
2285
    return (ipa_compare(new_bgp->cf->remote_ip, old_bgp->cf->remote_ip) < 0);
2286
}
2287

    
2288
//TODO two route are mergiable? take care of that
2289
int
2290
bgp_rte_mergable(rte *pri, rte *sec)
2291
{
2292
    struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->attrs->src->proto;
2293
    struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->attrs->src->proto;
2294
    eattr *x, *y;
2295
    u32 p, s;
2296

    
2297
    /* Skip suppressed routes (see bgp_rte_recalculate()) */
2298
    if (pri->u.bgp.suppressed != sec->u.bgp.suppressed)
2299
        return 0;
2300

    
2301
    /* RFC 4271 9.1.2.1. Route resolvability test */
2302
    if (!rte_resolvable(sec))
2303
        return 0;
2304

    
2305
    /* Start with local preferences */
2306
    x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
2307
    y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
2308
    p = x ? x->u.data : pri_bgp->cf->default_local_pref;
2309
    s = y ? y->u.data : sec_bgp->cf->default_local_pref;
2310
    if (p != s)
2311
        return 0;
2312

    
2313
    /* RFC 4271 9.1.2.2. a)  Use AS path lengths */
2314
    if (pri_bgp->cf->compare_path_lengths || sec_bgp->cf->compare_path_lengths)
2315
    {
2316
        x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
2317
        y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
2318
        p = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
2319
        s = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
2320

    
2321
        if (p != s)
2322
            return 0;
2323

    
2324
//    if (DELTA(p, s) > pri_bgp->cf->relax_multipath)
2325
//      return 0;
2326
    }
2327

    
2328
    /* RFC 4271 9.1.2.2. b) Use origins */
2329
    x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN));
2330
    y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN));
2331
    p = x ? x->u.data : ORIGIN_INCOMPLETE;
2332
    s = y ? y->u.data : ORIGIN_INCOMPLETE;
2333
    if (p != s)
2334
        return 0;
2335

    
2336
    /* RFC 4271 9.1.2.2. c) Compare MED's */
2337
    if (pri_bgp->cf->med_metric || sec_bgp->cf->med_metric ||
2338
        (bgp_get_neighbor(pri) == bgp_get_neighbor(sec)))
2339
    {
2340
        x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
2341
        y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC));
2342
        p = x ? x->u.data : pri_bgp->cf->default_med;
2343
        s = y ? y->u.data : sec_bgp->cf->default_med;
2344
        if (p != s)
2345
            return 0;
2346
    }
2347

    
2348
    /* RFC 4271 9.1.2.2. d) Prefer external peers */
2349
    if (pri_bgp->is_interior != sec_bgp->is_interior)
2350
        return 0;
2351

    
2352
    /* RFC 4271 9.1.2.2. e) Compare IGP metrics */
2353
    p = pri_bgp->cf->igp_metric ? pri->attrs->igp_metric : 0;
2354
    s = sec_bgp->cf->igp_metric ? sec->attrs->igp_metric : 0;
2355
    if (p != s)
2356
        return 0;
2357

    
2358
    /* Remaining criteria are ignored */
2359

    
2360
    return 1;
2361
}
2362

    
2363

    
2364
static inline int
2365
        same_group(rte *r, u32 lpref, u32 lasn)
2366
{
2367
return (r->pref == lpref) && (bgp_get_neighbor(r) == lasn);
2368
}
2369

    
2370
static inline int
2371
use_deterministic_med(rte *r)
2372
{
2373
    struct proto *P = r->attrs->src->proto;
2374
    return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
2375
}
2376

    
2377
int
2378
bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
2379
{
2380
    //log(L_INFO "hello, bgp_rte_recalculate");
2381
rte *r, *s;
2382
rte *key = new ? new : old;
2383
u32 lpref = key->pref;
2384
u32 lasn = bgp_get_neighbor(key);
2385
int old_is_group_best = 0;
2386

    
2387
/*
2388
 * Proper RFC 4271 path selection is a bit complicated, it cannot be
2389
 * implemented just by rte_better(), because it is not a linear
2390
 * ordering. But it can be splitted to two levels, where the lower
2391
 * level chooses the best routes in each group of routes from the
2392
 * same neighboring AS and higher level chooses the best route (with
2393
 * a slightly different ordering) between the best-in-group routes.
2394
 *
2395
 * When deterministic_med is disabled, we just ignore this issue and
2396
 * choose the best route by bgp_rte_better() alone. If enabled, the
2397
 * lower level of the route selection is done here (for the group
2398
 * to which the changed route belongs), all routes in group are
2399
 * marked as suppressed, just chosen best-in-group is not.
2400
 *
2401
 * Global best route selection then implements higher level by
2402
 * choosing between non-suppressed routes (as they are always
2403
 * preferred over suppressed routes). Routes from BGP protocols
2404
 * that do not set deterministic_med are just never suppressed. As
2405
 * they do not participate in the lower level selection, it is OK
2406
 * that this fn is not called for them.
2407
 *
2408
 * The idea is simple, the implementation is more problematic,
2409
 * mostly because of optimizations in rte_recalculate() that
2410
 * avoids full recalculation in most cases.
2411
 *
2412
 * We can assume that at least one of new, old is non-NULL and both
2413
 * are from the same protocol with enabled deterministic_med. We
2414
 * group routes by both neighbor AS (lasn) and preference (lpref),
2415
 * because bgp_rte_better() does not handle preference itself.
2416
 */
2417

    
2418
/* If new and old are from different groups, we just process that
2419
   as two independent events */
2420
if (new && old && !same_group(old, lpref, lasn))
2421
{
2422
int i1, i2;
2423
i1 = bgp_rte_recalculate(table, net, NULL, old, old_best);
2424
i2 = bgp_rte_recalculate(table, net, new, NULL, old_best);
2425
return i1 || i2;
2426
}
2427

    
2428
/*
2429
 * We could find the best-in-group and then make some shortcuts like
2430
 * in rte_recalculate, but as we would have to walk through all
2431
 * net->routes just to find it, it is probably not worth. So we
2432
 * just have two simpler fast cases that use just the old route.
2433
 * We also set suppressed flag to avoid using it in bgp_rte_better().
2434
 */
2435
//log(L_INFO "sono in bgp_rte_recalculate");
2436
if (new)
2437
new->u.bgp.suppressed = 1;
2438

    
2439
if (old)
2440
{
2441
old_is_group_best = !old->u.bgp.suppressed;
2442
old->u.bgp.suppressed = 1;
2443
int new_is_better = new && bgp_rte_better(new, old);
2444

    
2445
/* The first case - replace not best with worse (or remove not best) */
2446
if (!old_is_group_best && !new_is_better)
2447
return 0;
2448

    
2449
/* The second case - replace the best with better */
2450
if (old_is_group_best && new_is_better)
2451
{
2452
//log(L_INFO "replace the best with better");
2453
/* new is best-in-group, the see discussion below - this is
2454
a special variant of NBG && OBG. From OBG we can deduce
2455
that same_group(old_best) iff (old == old_best)  */
2456
new->u.bgp.suppressed = 0;
2457
return (old == old_best);
2458
}
2459
}
2460

    
2461
/* The default case - find a new best-in-group route */
2462
r = new; /* new may not be in the list */
2463
for (s=net->routes; rte_is_valid(s); s=s->next)
2464
if (use_deterministic_med(s) && same_group(s, lpref, lasn))
2465
{
2466
s->u.bgp.suppressed = 1;
2467
if (!r || bgp_rte_better(s, r))
2468
r = s;
2469
}
2470

    
2471
/* Simple case - the last route in group disappears */
2472
if (!r)
2473
return 0;
2474

    
2475
/* Found best-in-group */
2476
r->u.bgp.suppressed = 0;
2477

    
2478
/*
2479
 * There are generally two reasons why we have to force
2480
 * recalculation (return 1): First, the new route may be wrongfully
2481
 * chosen to be the best in the first case check in
2482
 * rte_recalculate(), this may happen only if old_best is from the
2483
 * same group. Second, another (different than new route)
2484
 * best-in-group is chosen and that may be the proper best (although
2485
 * rte_recalculate() without ignore that possibility).
2486
 *
2487
 * There are three possible cases according to whether the old route
2488
 * was the best in group (OBG, stored in old_is_group_best) and
2489
 * whether the new route is the best in group (NBG, tested by r == new).
2490
 * These cases work even if old or new is NULL.
2491
 *
2492
 * NBG -> new is a possible candidate for the best route, so we just
2493
 *        check for the first reason using same_group().
2494
 *
2495
 * !NBG && OBG -> Second reason applies, return 1
2496
 *
2497
 * !NBG && !OBG -> Best in group does not change, old != old_best,
2498
 *                 rte_better(new, old_best) is false and therefore
2499
 *                 the first reason does not apply, return 0
2500
 */
2501

    
2502
if (r == new)
2503
return old_best && same_group(old_best, lpref, lasn);
2504
else
2505
return old_is_group_best;
2506
}
2507

    
2508

    
2509
/*
2510
 * Reconstruct AS_PATH and AGGREGATOR according to RFC 6793 4.2.3
2511
 */
2512
static void
2513
        bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool)
2514
{
2515
eattr *p2 = bgp_find_attr(*attrs, BA_AS_PATH);
2516
eattr *p4 = bgp_find_attr(*attrs, BA_AS4_PATH);
2517
eattr *a2 = bgp_find_attr(*attrs, BA_AGGREGATOR);
2518
eattr *a4 = bgp_find_attr(*attrs, BA_AS4_AGGREGATOR);
2519

    
2520
/* First, unset AS4_* attributes */
2521
if (p4) bgp_unset_attr(attrs, pool, BA_AS4_PATH);
2522
if (a4) bgp_unset_attr(attrs, pool, BA_AS4_AGGREGATOR);
2523

    
2524
/* Handle AGGREGATOR attribute */
2525
if (a2 && a4)
2526
{
2527
u32 a2_asn = get_u32(a2->u.ptr->data);
2528

    
2529
/* If routes were aggregated by an old router, then AS4_PATH and
2530
   AS4_AGGREGATOR are invalid. In that case we give up. */
2531
if (a2_asn != AS_TRANS)
2532
return;
2533

    
2534
/* Use AS4_AGGREGATOR instead of AGGREGATOR */
2535
a2->u.ptr = a4->u.ptr;
2536
}
2537

    
2538
/* Handle AS_PATH attribute */
2539
if (p2 && p4)
2540
{
2541
/* Both as_path_getlen() and as_path_cut() take AS_CONFED* as zero length */
2542
int p2_len = as_path_getlen(p2->u.ptr);
2543
int p4_len = as_path_getlen(p4->u.ptr);
2544

    
2545
/* AS_PATH is too short, give up */
2546
if (p2_len < p4_len)
2547
return;
2548

    
2549
/* Merge AS_PATH and AS4_PATH */
2550
as_path_cut(p2->u.ptr, p2_len - p4_len);
2551
p2->u.ptr = as_path_merge(pool, p2->u.ptr, p4->u.ptr);
2552
}
2553
}
2554

    
2555
/**
2556
 * Function to get the information about an attr
2557
 * @param a
2558
 * @param buf
2559
 * @param buflen
2560
 * @return
2561
 */
2562
int
2563
bgp_get_attr(eattr *a, byte *buf, int buflen)
2564
{
2565
    uint i = EA_ID(a->id);
2566
    const struct bgp_attr_desc *d;
2567
    int len;
2568

    
2569
    if (bgp_attr_known(i))
2570
    {
2571
        d = &bgp_attr_table[i];
2572
        len = bsprintf(buf, "%s", d->name);
2573
        buf += len;
2574
        if (d->format)
2575
        {
2576
            *buf++ = ':';
2577
            *buf++ = ' ';
2578
            d->format(a, buf, buflen - len - 2);
2579
            return GA_FULL;
2580
        }
2581
        return GA_NAME;
2582
    }
2583

    
2584
    bsprintf(buf, "%02x%s", i, (a->flags & BAF_TRANSITIVE) ? " [t]" : "");
2585
    return GA_NAME;
2586
}
2587

    
2588
/**
2589
 * Get attribute of a specific route
2590
 * @param e
2591
 * @param buf
2592
 * @param attrs
2593
 */
2594
void
2595
bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
2596
{
2597
    eattr *p = ea_find(attrs, EA_CODE(EAP_BGP, BA_AS_PATH));
2598
    eattr *o = ea_find(attrs, EA_CODE(EAP_BGP, BA_ORIGIN));
2599
    u32 origas;
2600

    
2601
    buf += bsprintf(buf, " (%d", e->pref);
2602

    
2603
    if (e->u.bgp.suppressed)
2604
        buf += bsprintf(buf, "-");
2605

    
2606
    if (e->attrs->hostentry)
2607
    {
2608
        if (!rte_resolvable(e))
2609
            buf += bsprintf(buf, "/-");
2610
        else if (e->attrs->igp_metric >= IGP_METRIC_UNKNOWN)
2611
            buf += bsprintf(buf, "/?");
2612
        else
2613
            buf += bsprintf(buf, "/%d", e->attrs->igp_metric);
2614
    }
2615
    buf += bsprintf(buf, ") [");
2616

    
2617
    if (p && as_path_get_last(p->u.ptr, &origas))
2618
        buf += bsprintf(buf, "AS%u", origas);
2619
    if (o)
2620
        buf += bsprintf(buf, "%c", "ie?"[o->u.data]);
2621
    strcpy(buf, "]");
2622
}