summaryrefslogtreecommitdiff
path: root/nest/a-path.c
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2020-05-18 16:25:08 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2020-05-18 16:25:08 +0200
commitec430a7feefd3b32ee39c641a48c44528d0eab25 (patch)
tree2faac868b9ad1daddc3bea6253ac7d1de7560323 /nest/a-path.c
parent5fc8407177fd34f2d57441a8ff9a068f4162fbfb (diff)
Nest: Implement BGP path mask loop operator
Implement regex-like '+' operator in BGP path masks to match previous path mask item multiple times. This is useful as ASNs may appear multiple times in paths due to path prepending for traffic engineering purposes.
Diffstat (limited to 'nest/a-path.c')
-rw-r--r--nest/a-path.c63
1 files changed, 42 insertions, 21 deletions
diff --git a/nest/a-path.c b/nest/a-path.c
index cffd46ab..2e34a3d1 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -727,7 +727,7 @@ parse_path(const struct adata *path, struct pm_pos *pp)
}
static int
-pm_match(struct pm_pos *pos, u32 asn, u32 asn2)
+pm_match_val(const struct pm_pos *pos, u32 asn, u32 asn2)
{
u32 gas;
if (! pos->set)
@@ -749,7 +749,7 @@ pm_match(struct pm_pos *pos, u32 asn, u32 asn2)
}
static int
-pm_match_set(struct pm_pos *pos, const struct f_tree *set)
+pm_match_set(const struct pm_pos *pos, const struct f_tree *set)
{
struct f_val asn = { .type = T_INT };
@@ -773,25 +773,34 @@ pm_match_set(struct pm_pos *pos, const struct f_tree *set)
return 0;
}
+static inline int
+pm_match(const struct pm_pos *pos, const struct f_path_mask_item *mask, u32 asn, u32 asn2)
+{
+ return ((mask->kind == PM_QUESTION) ||
+ ((mask->kind != PM_ASN_SET) ?
+ pm_match_val(pos, asn, asn2) :
+ pm_match_set(pos, mask->set)));
+}
+
static void
-pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
+pm_mark(struct pm_pos *pos, int *i, int plen, int *nl, int *nh)
{
- int j;
+ int j = *i;
- if (pos[i].set)
- pos[i].mark = 1;
+ if (pos[j].set)
+ do { pos[j].mark = 1; j++; }
+ while ((j < plen) && pos[j].set);
+ else
+ j++;
- for (j = i + 1; (j < plen) && pos[j].set && (! pos[j].mark); j++)
- pos[j].mark = 1;
pos[j].mark = 1;
- /* We are going downwards, therefore every mark is
- new low and just the first mark is new high */
-
- *nl = i + (pos[i].set ? 0 : 1);
+ /* Update low, high based on first and last marked pos */
+ int l = pos[*i].set ? *i : j;
- if (*nh < 0)
- *nh = j;
+ *nl = (*nl < 0) ? l : MIN(*nl, l);
+ *nh = MAX(*nh, j);
+ *i = j;
}
/* AS path matching is nontrivial. Because AS path can
@@ -821,7 +830,7 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
{
struct pm_pos pos[2048 + 1];
int plen = parse_path(path, pos);
- int l, h, i, nh, nl;
+ int l, h, i, nh, nl, last, loop;
u32 val = 0;
u32 val2 = 0;
@@ -831,7 +840,7 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
pos[plen].set = 0;
pos[plen].mark = 0;
- l = h = 0;
+ l = h = loop = 0;
pos[0].mark = 1;
for (uint m=0; m < mask->len; m++)
@@ -847,6 +856,10 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
h = plen;
break;
+ case PM_LOOP:
+ loop = 1;
+ break;
+
case PM_ASN: /* Define single ASN as ASN..ASN - very narrow interval */
val2 = val = mask->item[m].asn;
goto step;
@@ -860,15 +873,22 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
case PM_ASN_SET:
step:
nh = nl = -1;
+ last = plen;
for (i = h; i >= l; i--)
if (pos[i].mark)
{
pos[i].mark = 0;
- if ((mask->item[m].kind == PM_QUESTION) ||
- ((mask->item[m].kind != PM_ASN_SET) ?
- pm_match(pos + i, val, val2) :
- pm_match_set(pos + i, mask->item[m].set)))
- pm_mark(pos, i, plen, &nl, &nh);
+ int j = i;
+
+ match:
+ if (pm_match(pos + j, &mask->item[m], val, val2))
+ {
+ pm_mark(pos, &j, plen, &nl, &nh);
+ if (loop && (j < last))
+ goto match;
+ }
+
+ last = i;
}
if (nh < 0)
@@ -876,6 +896,7 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
h = nh;
l = nl;
+ loop = 0;
break;
}
}