+
+static void
+apply_r_p_redirect__(
Same here, I think I prefer apply_routing_protocols_redirect__().
+ const char *s_addr, const char *redirect_port_name, int
protocol_flags,
+ bool is_ipv6, struct ovn_port *ls_peer, struct lflow_table
*lflows,
+ struct ds *match, struct ds *actions)
+{
+ if (protocol_flags & REDIRECT_BGP) {
+ build_r_p_redirect_rule__(s_addr, redirect_port_name, 179,
"tcp",
+ is_ipv6, ls_peer, lflows, match,
actions);
+ }
+
+ if (protocol_flags & REDIRECT_BFD) {
+ build_r_p_redirect_rule__(s_addr, redirect_port_name,
3784, "udp",
+ is_ipv6, ls_peer, lflows, match,
actions);
+ }
+
+ /* Because the redirected port shares IP and MAC addresses
with the LRP,
+ * special consideration needs to be given to the signaling
protocols. */
+ if (is_ipv6) {
+ /* Ensure that redirect port receives copy of NA messages
destined to
+ * its IP.*/
+ ds_clear(match);
+ ds_clear(actions);
+ ds_put_format(actions, "clone { outport = \"%s\"; output;
};",
+ redirect_port_name);
+ ds_put_format(match, "ip6.dst == %s && nd_na", s_addr);
+ ovn_lflow_add(lflows, ls_peer->od, S_SWITCH_IN_L2_LKUP,
100,
+ ds_cstr(match),
+ ds_cstr(actions),
+ ls_peer->lflow_ref);
+ } else {
+ /* Ensure that redirect port receives copy of ARP replies
destined to
+ * its IP */
+ ds_clear(match);
+ ds_clear(actions);
+ ds_put_format(actions, "clone { outport = \"%s\"; output;
};",
+ redirect_port_name);
+ ds_put_format(match, "arp.op == 2 && arp.tpa == %s",
s_addr);
+ ovn_lflow_add(lflows, ls_peer->od, S_SWITCH_IN_L2_LKUP,
100,
+ ds_cstr(match),
+ ds_cstr(actions),
+ ls_peer->lflow_ref);
+
Nit: no need for newline.
+ }
+}
+
+static int
+parse_redirected_routing_protocols(struct ovn_port *lrp) {
+ int redirected_protocol_flags = 0;
+ const char *redirect_protocols = smap_get(&lrp->nbrp->options,
+ "routing-
protocols");
+ if (redirect_protocols == NULL) {
+ return redirected_protocol_flags;
+ }
+
+ char *proto;
+ char *save_ptr = NULL;
+ char *tokstr = xstrdup(redirect_protocols);
+ for (proto = strtok_r(tokstr, ",", &save_ptr); proto != NULL;
+ proto = strtok_r(NULL, ",", &save_ptr)) {
+ if (!strcmp(proto, "BGP")) {
+ redirected_protocol_flags |= REDIRECT_BGP;
+ continue;
+ }
+
+ if (!strcmp(proto, "BFD")) {
+ redirected_protocol_flags |= REDIRECT_BFD;
+ continue;
+ }
Nit: missing newlines.
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
5);
+ VLOG_WARN_RL(&rl, "Option 'routing-protocols' encountered
unknown "
+ "value %s",
+ proto);
+ }
+ free(tokstr);
+ return redirected_protocol_flags;
+}
+
+static void
+build_lrouter_routing_protocol_redirect(
+ struct ovn_port *op, struct lflow_table *lflows,
+ struct ds *match, struct ds *actions)
+{
+ /* LRP has to have a peer.*/
+ if (op->peer == NULL) {
+ return;
+ }
Nit: missing newline.
+ /* LRP has to have NB record.*/
+ if (op->nbrp == NULL) {
+ return;
+ }
+
+ /* Proceed only for LRPs that have 'routing-protocol-redirect'
option set.
+ * Value of this option is the name of LSP to which the
routing protocol
+ * traffic will be redirected. */
+ const char *redirect_port = smap_get(&op->nbrp->options,
+ "routing-protocol-
redirect");
+ if (redirect_port == NULL) {
+ return;
+ }
+
+ if (op->cr_port != NULL) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
5);
+ VLOG_WARN_RL(&rl, "Option 'routing-protocol-redirect' is
not "
+ "supported on Distributed Gateway Port
'%s'",
+ op->key);
+ return;
+ }
+
+ /* Ensure that LSP, to which the routing protocol traffic is
redirected,
+ * exists.*/
Nit: missing space after '.'
+ struct ovn_port *peer_lsp;
+ bool redirect_port_exists = false;
+ HMAP_FOR_EACH (peer_lsp, dp_node, &op->peer->od->ports) {
+ size_t peer_lsp_s = strlen(peer_lsp->key);
+ if (peer_lsp_s == strlen(redirect_port)
+ && !strncmp(peer_lsp->key, redirect_port,
peer_lsp_s)){
+ redirect_port_exists = true;
+ break;
+ }
+ }
+
+ if (!redirect_port_exists) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
5);
+ VLOG_WARN_RL(&rl, "Option 'routing-protocol-redirect' set
on Logical "
+ "Router Port '%s' refers to non-existent
Logical "
+ "Switch Port. Routing protocol
redirecting won't be "
+ "configured.",
+ op->key);
+ return;
+ }
+
+
Nit: too many new lines.
+ int redirected_protocols =
parse_redirected_routing_protocols(op);
+ if (!redirected_protocols) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
5);
+ VLOG_WARN_RL(&rl, "Option 'routing-protocol-redirect' is
set on "
+ "Logical Router Port '%s' but no known
protocols "
+ "were set via 'routing-protocols'
options. This "
+ "configuration has no effect.",
+ op->key);
+ return;
+ }
+
+ /* Redirecte traffic destined for LRP's IPs and the specified
routing
Typo: redirecte
+ * protocol ports to the port defined in 'routing-protocol-
redirect'
+ * option.*/
+ for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
+ const char *ip_s = op->lrp_networks.ipv4_addrs[i].addr_s;
+ apply_r_p_redirect__(ip_s, redirect_port,
redirected_protocols, false,
+ op->peer, lflows,match, actions);
+ }
+ for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
+ const char *ip_s = op->lrp_networks.ipv6_addrs[i].addr_s;
+ apply_r_p_redirect__(ip_s, redirect_port,
redirected_protocols, true,
+ op->peer, lflows,match,
actions);
+ }
+
+ /* Drop ARP replies and IPv6 RA/NA packets originating from
+ * 'routing-protocol-redirect' LSP. As this port shares IP and
MAC
+ * addresses with LRP, we don't want to create duplicates.*/
+ ds_clear(match);
+ ds_put_format(match, "inport == \"%s\" && arp.op == 2",
redirect_port);
+ ovn_lflow_add(lflows, op->peer->od,
S_SWITCH_IN_CHECK_PORT_SEC, 80,
+ ds_cstr(match),
+ REGBIT_PORT_SEC_DROP " = 1; next;",
+ op->peer->lflow_ref);
+
+ ds_clear(match);
+ ds_put_format(match, "inport == \"%s\" && nd_na",
redirect_port);
+ ovn_lflow_add(lflows, op->peer->od,
S_SWITCH_IN_CHECK_PORT_SEC, 80,
+ ds_cstr(match),
+ REGBIT_PORT_SEC_DROP " = 1; next;",
+ op->peer->lflow_ref);
+
+ ds_clear(match);
+ ds_put_format(match, "inport == \"%s\" && nd_ra",
redirect_port);
+ ovn_lflow_add(lflows, op->peer->od,
S_SWITCH_IN_CHECK_PORT_SEC, 80,
+ ds_cstr(match),
+ REGBIT_PORT_SEC_DROP " = 1; next;",
+ op->peer->lflow_ref);
+}
+
/* This function adds ARP resolve flows related to a LSP. */
static void
build_arp_resolve_flows_for_lsp(
@@ -16003,6 +16218,8 @@
build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op,
lsi->meter_groups, op->lflow_ref);
build_lrouter_icmp_packet_toobig_admin_flows(op, lsi->lflows,
&lsi->match,
&lsi->actions,
op->lflow_ref);
+ build_lrouter_routing_protocol_redirect(op, lsi->lflows,
+ &lsi->match, &lsi-
actions);
}
static void *
diff --git a/northd/northd.h b/northd/northd.h
index d4a8d75ab..691c23f01 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -89,6 +89,13 @@ ods_size(const struct ovn_datapaths *datapaths)
bool od_has_lb_vip(const struct ovn_datapath *od);
+/* List of routing and routing-related protocols which
+ * OVN is capable of redirecting from LRP to specific LSP. */
+enum redirected_routing_protcol_flag_type {
+ REDIRECT_BGP = (1 << 0),
+ REDIRECT_BFD = (1 << 1),
+};
+
struct tracked_ovn_ports {
/* tracked created ports.
* hmapx node data is 'struct ovn_port *' */
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index b06b09ac5..250c602f2 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -284,6 +284,32 @@
dropped in the next stage.
</li>
+ <li>
+ <p>
+ For each logical port that's defined as a target of
routing protocol
+ redirecting (via <code>routing-protocol-redirect</code>
option set on
+ Logical Router Port), a filter is set in place that
disallows
+ following traffic exiting this port:
+ </p>
+ <ul>
+ <li>
+ ARP replies
+ </li>
+ <li>
+ IPv6 Neighbor Discovery - Router Advertisements
+ </li>
+ <li>
+ IPv6 Neighbor Discovery - Neighbor Advertisements
+ </li>
+ </ul>
+ <p>
+ Since this port shares IP and MAC addresses with the
Logical Router
+ Port, we wan't to prevent duplicate replies and
advertisements. This
+ is achieved by a rule with priority 80 that sets
+ <code>REGBIT_PORT_SEC_DROP" = 1; next;"</code>.
+ </p>
+ </li>
+
<li>
For each (enabled) vtep logical port, a priority 70 flow
is added which
matches on all packets and applies the action
@@ -1949,6 +1975,34 @@ output;
on the logical switch.
</li>
+ <li>
+ <p>
+ For any logical port that's defined as a target of
routing protocol
+ redirecting (via <code>routing-protocol-redirect</code>
option set on
+ Logical Router Port), we redirect the traffic related to
protocols
+ specified in <code>routing-protocols</code> option. It's
acoomplished
+ with following priority-100 flows:
+ <p>
This should be </p>.
+ <ul>
+ <li>
+ Flows that match Logical Router Port's IPs and
destination port of
+ the routing daemon are redirected to this port to
allow external
+ peers' connection to the daemon listening on this
port.
+ </li>
+ <li>
+ Flows that match Logical Router Port's IPs and source
port of
+ the routing daemon are redirected to this port to
allow replies
+ from the peers.
+ </li>
+ </ul>
+ <p>
+ In addition to this, we add priority-100 rules that
+ <code>clone</code> ARP replies and IPv6 Neighbor
Advertisements to
+ this port as well. These allow to build proper ARP/IPv6
neighbor
+ list on this port.
+ </p>
+ </li>
+
<li>
Priority-90 flows for transit switches that forward
registered
IP multicast traffic to their corresponding multicast
group , which
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 9552534f6..092195473 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -3440,6 +3440,48 @@ or
</p>
</column>
+ <column name="options" key="routing-protocol-redirect"
+ type='{"type": "string"}'>
+ <p>
+ NOTE: this feature is experimental and may be subject to
+ removal/change in the future.
+ </p>
+ <p>
+ This option expects a name of a Logical Switch Port
that's present
+ in the peer's Logical Switch. If set, it causes any
traffic
+ that's destined for Logical Router Port's IP addresses
(including
+ its IPv6 LLA) and the ports associated with routing
protocols defined
+ ip <code>routing-protocols</code> option, to be
redirected
+ to the specified Logical Switch Port.
+
+ This allows external routing daemons to be bound to a
port in OVN's
+ Logical Switch and act as if they were listening on
Logical Router
+ Port's IP addresses.
+ </p>
+ </column>
+
+ <column name="options" key="routing-protocols"
type='{"type": "string"}'>
+ <p>
+ NOTE: this feature is experimental and may be subject to
+ removal/change in the future.
+ </p>
+ <p>
+ This option expects a comma-separated list of routing,
and
+ routing-related protocols, whose control plane traffic
will be
+ redirected to a port specified in
+ <code>routing-protocol-redirect</code> option. Currently
supported
+ options are:
+ </p>
+ <ul>
+ <li>
+ <code>BGP</code> (forwards TCP port 179)
+ </li>
+ <li>
+ <code>BFD</code> (forwards UDP port 3748)
+ </li>
+ <ul>
This should be </ul>.
The rest looks OK to me. You can find the rebased version, including
these minor nits fixed here:
https://github.com/dceara/ovn/commits/review-pws418655-bgp-redirect-v5/
If the small changes I made look OK to you feel free to squash them
in
and post v6 with my:
Acked-by: Dumitru Ceara<[email protected]>
Thanks,
Dumitru