Skip to content

Commit

Permalink
Merge pull request #46 from iij/floatlink-route
Browse files Browse the repository at this point in the history
floatlink route add ... を変換する。
  • Loading branch information
tsahara authored Jan 17, 2025
2 parents 5eb07f7 + ac3ca5e commit de1a8ce
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 19 deletions.
153 changes: 134 additions & 19 deletions seil2recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ class Converter {
fun(deferconv);
});
this.conversions.push(deferconv);

this.note.tconf.expand();
}

static defer(fun) {
Expand All @@ -139,8 +141,8 @@ class Note {
this.params = new Map();
this.ifindex = new Map(); // (prefix) -> (interface) -> (index)
this.memo = new Map();
this.deps = new DependencySet();
this.dst = new Device(target_device);
this.tconf = new TreeConfig();

this.memo.set('bridge.group', new Map());
this.memo.set('floatlink.interfaces', []);
Expand Down Expand Up @@ -303,8 +305,8 @@ class Conversion {
//
// Proxy methods
//
get deps() {
return this.note.deps;
get tconf() {
return this.note.tconf;
}

get_index(prefix, zero_origin) {
Expand Down Expand Up @@ -630,31 +632,134 @@ class Error {
}
}

class DependencySet {
class TreeConfig {
constructor() {
this.floatlink = { url: null, iflist: [] };
this.root = new Map();
}

get(symbols) {
let node = this.root;
for (const sym of symbols) {
if (!(node instanceof Map)) {
throw new Error(`bad TreeConfig keys: ${symbols}`);
}
node = node.get(sym);
if (node == undefined) {
return undefined;
}
}
return node; // a TreeConfigValue or a Map (subtree).
}

add_floatlink_name_service(conv, url) {
this.floatlink.url = { conv: conv, value: url };
this.emit();
match(pattern) {
let node = this.root;
let idx = 0;
for (const sym of pattern) {
if (!(node instanceof Map)) {
throw new Error(`bad TreeConfig matcher: ${pattern}`);
}
if (sym == '*') {
break;
} else {
node = node.get(sym);
if (node == undefined) {
return [];
}
}
idx += 1;
}

const candidates = Array.from(node.keys());
let retval = [];
for (const cand of candidates) {
const symbols = Array.from(pattern);
symbols[idx] = cand;
const cval = this.get(symbols)
if (cval) {
retval.push([cand, cval]);
}
}

return retval;
}

add_floatlink_iface(conv, ifname) {
this.floatlink.iflist.push({ conv: conv, value: ifname})
this.emit();
set(labels, val, conv) {
let node = this.root;
let index = 0;
for (const label of labels) {
if (index == labels.length - 1) {
const oldval = node.get(label);
if (oldval instanceof Map) {
throw new Error(`TreeConfig leaf is a Map: ${labels}`);
}
node.set(label, new TreeConfigValue(val, conv));
return;
} else {
let child = node.get(label)
if (child instanceof Map) {
node = child;
} else if (child == undefined) {
child = new Map();
node.set(label, child);
node = child;
} else {
throw new Error(`value found on an intermediate node of TreeConfig: ${labels} index ${index}`);
}
}
index += 1;
}
}

emit() {
if (this.floatlink.url) {
this.floatlink.iflist.forEach(iface => {
iface.conv.add(`interface.${iface.value}.floatlink.name-service`, this.floatlink.url.value);
set_params(labels, params, conv) {
const name = params['*NAME*'];
for (const key in params) {
this.set(labels.concat(name, key), params[key], conv);
}
}

expand_leafmap(leafmap, rules) {
for (const key in rules) {
const cval = leafmap.get(key);
if (cval) {
cval.conv.add(rules[key], cval.str);
}
}
}

expand() {
this.expand_floatlink();
}

expand_floatlink() {
const ns = this.get(['floatlink', 'name-service']);
if (ns == null) {
return;
}

for (const [m, cval] of this.match(['interface', '*', 'floatlink', 'my-node-id'])) {
cval.conv.add(`interface.${m}.floatlink.name-service`, ns.str);
}

for (const [_, leafmap] of this.match(['floatlink', 'route', '*'])) {
const k = ns.conv.get_index('route.ipv4');
ns.conv.add(`${k}.floatlink.name-service`, ns.str);
this.expand_leafmap(leafmap, {
'*NAME*': `${k}.floatlink.destination`,
'distance': `${k}.distance`,
'floatlink-key': `${k}.floatlink.key`,
'gateway': `${k}.gateway`,
});
this.floatlink.iflist = [];
}
}
}

class TreeConfigValue {
constructor(str, conv) {
this.str = str;
this.conv = conv;
}
}

function tokenize(line) {
const tokens = []
let token = ""
Expand Down Expand Up @@ -2059,10 +2164,20 @@ Converter.rules['floatlink'] = {
// seil3 系専用サーバの URL が書いてある場合は、汎用サーバの
// URL に置き換える。
let url = tokens[3].replace('floatlink-seil.', 'floatlink.');
conv.deps.add_floatlink_name_service(conv, url);
conv.tconf.set(['floatlink', 'name-service'], url, conv);
}
},
'route': 'notsupported',

'route': {
'add': (conv, tokens) => {
const params = conv.read_params(null, tokens, 3, {
'distance': true,
'floatlink-key': true,
'gateway': true,
});
conv.tconf.set_params(['floatlink', 'route'], params, conv);
}
}
};

Converter.rules['hostname'] = (conv, tokens) => {
Expand Down Expand Up @@ -2462,7 +2577,7 @@ Converter.rules['interface'] = {
conv.add(`interface.${ifname}.floatlink.my-node-id`, tokens[4]);

// my-node-id は必須キーなので、このタイミングで書く。
conv.deps.add_floatlink_iface(conv, ifname);
conv.tconf.set(['interface', ifname, 'floatlink', 'my-node-id'], tokens[4], conv);
},
'nat-traversal': (conv, tokens) => {
const ifname = conv.ifmap(tokens[1]);
Expand Down
48 changes: 48 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,19 @@ describe('floatlink', () => {
floatlink.ike.proposal.phase2.pfs-group: modp3072
`);
});

it('route', () => {
assertconv(`
floatlink name-service add https://example.jp/floatlink
floatlink route add NODE1 gateway 1.2.3.4 floatlink-key FLOATLINKKEY1 distance 123
---
route.ipv4.100.floatlink.destination: NODE1
route.ipv4.100.floatlink.key: FLOATLINKKEY1
route.ipv4.100.floatlink.name-service: https://example.jp/floatlink
route.ipv4.100.distance: 123
route.ipv4.100.gateway: 1.2.3.4
`);
});
});

describe('hostname', () => {
Expand Down Expand Up @@ -2996,6 +3009,41 @@ describe('order issues', () => {
interface.ipsec1.floatlink.name-service: https://example.com/
`);
});

it('multiple floatlink interfaces', () => {
assertconv(`
interface ipsec0 floatlink my-node-id MYNODE0
floatlink name-service add https://example.com/
interface ipsec1 floatlink my-node-id MYNODE1
---
interface.ipsec0.floatlink.my-node-id: MYNODE0
interface.ipsec0.floatlink.name-service: https://example.com/
interface.ipsec1.floatlink.my-node-id: MYNODE1
interface.ipsec1.floatlink.name-service: https://example.com/
`);

assertconv(`
floatlink name-service add https://example.com/
interface ipsec0 floatlink my-node-id MYNODE0
interface ipsec1 floatlink my-node-id MYNODE1
---
interface.ipsec0.floatlink.my-node-id: MYNODE0
interface.ipsec0.floatlink.name-service: https://example.com/
interface.ipsec1.floatlink.my-node-id: MYNODE1
interface.ipsec1.floatlink.name-service: https://example.com/
`);

assertconv(`
interface ipsec0 floatlink my-node-id MYNODE0
interface ipsec1 floatlink my-node-id MYNODE1
floatlink name-service add https://example.com/
---
interface.ipsec0.floatlink.my-node-id: MYNODE0
interface.ipsec0.floatlink.name-service: https://example.com/
interface.ipsec1.floatlink.my-node-id: MYNODE1
interface.ipsec1.floatlink.name-service: https://example.com/
`);
});
});

describe('time2sec', () => {
Expand Down

0 comments on commit de1a8ce

Please sign in to comment.