For each lport, adds a priority 90 lflow in ls_in_port_sec and ls_out_port_sec stages to allow ipv6 traffic for - known ipv6 addresses - link local address of the lport - ip6 packet with ip6.src = :: and ip6.dst=ff02::/64 to allow ND packets.
Signed-off-by: Numan Siddique <[email protected]> --- lib/packets.h | 16 ++++++++++++++++ ovn/northd/ovn-northd.8.xml | 10 ++++++---- ovn/northd/ovn-northd.c | 46 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/lib/packets.h b/lib/packets.h index 31a4e92..7c28dfa 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -978,6 +978,22 @@ in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6) memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3); } +/* + * Generates ipv6 link local address from the given eth addr + * with prefix 'fe80::/64' and stores it in 'lla' + */ +static inline void +in6_generate_lla(struct eth_addr ea, struct in6_addr *lla) +{ + union ovs_16aligned_in6_addr *taddr = (void *) lla; + memset(taddr->be16, 0, sizeof(taddr->be16)); + taddr->be16[0] = htons(0xfe80); + taddr->be16[4] = htons(((ea.ea[0] ^ 0x02) << 8) | ea.ea[1]); + taddr->be16[5] = htons(ea.ea[2] << 8 | 0x00ff); + taddr->be16[6] = htons(0xfe << 8 | ea.ea[3]); + taddr->be16[7] = ea.be16[2]; +} + static inline void ipv6_multicast_to_ethernet(struct eth_addr *eth, const struct in6_addr *ip6) { diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml index 376356e..45e9237 100644 --- a/ovn/northd/ovn-northd.8.xml +++ b/ovn/northd/ovn-northd.8.xml @@ -154,8 +154,9 @@ </li> <li> - Priority 90 flow is added to allow all ipv6 traffic if it has - ipv6 address(es). + Priority 90 flow is added to allow ipv6 traffic if it has + ipv6 address(es) which match the <code>inport</code>, valid + <code>eth.src</code> and valid <code>ip6.src</code> address(es). </li> <li> @@ -321,8 +322,9 @@ output; <p> This is similar to the ingress port security logic in ingress table 0, but with important differences. Most obviously, <code>outport</code> and - <code>eth.dst</code> and <code>ip4.dst</code> are checked instead of - <code>inport</code>, <code>eth.src</code>, and <code>ip4.src</code>. + <code>eth.dst</code>, <code>ip4.dst</code> and <code>ip6.dst</code>are + checked instead of <code>inport</code>, <code>eth.src</code>, + <code>ip4.src</code> and <code>ip6.src</code>. Second, packets directed to broadcast or multicast <code>eth.dst</code> are always accepted instead of being subject to the port security rules; this is implemented through a priority-100 flow that matches on diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index b10b2e3..1201b78 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -1031,6 +1031,43 @@ build_port_security_ipv4_flow(enum ovn_pipeline pipeline, struct ds *match, ds_put_cstr(match, ")"); } +static void +build_port_security_ipv6_flow(enum ovn_pipeline pipeline, struct ds *match, + struct eth_addr ea, struct in6_addr *ipv6_addrs, + int n_ipv6_addrs) +{ + char *ip6_addr_field; + if (pipeline == P_IN) { + ip6_addr_field = "ip6.src"; + } + else { + ip6_addr_field = "ip6.dst"; + } + + char ip6_str[INET6_ADDRSTRLEN + 1]; + /* Allow link local address */ + struct in6_addr lla; + in6_generate_lla(ea, &lla); + memset(ip6_str, 0, sizeof(ip6_str)); + ipv6_string_mapped(ip6_str, &lla); + ds_put_format(match, " && ip6 && (%s == %s", ip6_addr_field, ip6_str); + + /* Allow ip6.src=:: and ip6.dst=ff02::/64 for ND packets */ + memset(ip6_str, 0, sizeof(ip6_str)); + struct in6_addr zero_in6_addr; + memset(&zero_in6_addr, 0, sizeof(struct in6_addr)); + ipv6_string_mapped(ip6_str, &zero_in6_addr); + + ds_put_format(match, " || (ip6.src == %s && ip6.dst == ff02::/64)", + ip6_str); + for(int i = 0; i < n_ipv6_addrs; i++) { + memset(ip6_str, 0, sizeof(ip6_str)); + ipv6_string_mapped(ip6_str, &ipv6_addrs[i]); + ds_put_format(match, " || %s == %s", ip6_addr_field, ip6_str); + } + ds_put_cstr(match, ")"); +} + /* * Build port security constraints on L2 and L3 address fields and add * logical flows to S_SWITCH_(IN/OUT)_PORT_SEC stage. @@ -1042,8 +1079,7 @@ build_port_security_ipv4_flow(enum ovn_pipeline pipeline, struct ds *match, * known ipv4 addresses. * - Add a priority 90 flow to allow ipv4 packets for known ipv4 addresses * - Add a priority 80 flow to drop arp (for ingress) and ip packets - * - Add a priority 90 flow to allow all ipv6 packets if port security - * has ipv6 address(es). + * - Add a priority 90 flow to allow ipv6 packets for known ipv6 addresses * - Add a priority 80 flow to drop ipv6 packets. * - Add a priority 50 flow to allow all other traffic with the matching * ethernet address. @@ -1141,12 +1177,12 @@ build_port_security(enum ovn_pipeline pipeline, struct ovn_port *op, ds_destroy(&match); if (ps->n_ipv6_addrs) { - /* XXX Need to add port security flows for ipv6. - * For now add a priority 90 flow to allow all ipv6 traffic */ ds_init(&match); - ds_put_format(&match, "%s == %s && %s == "ETH_ADDR_FMT" && ip6", + ds_put_format(&match, "%s == %s && %s == "ETH_ADDR_FMT, port_direction, op->json_key, eth_addr_field, ETH_ADDR_ARGS(ps->ea)); + build_port_security_ipv6_flow(pipeline, &match, ps->ea, + ps->ipv6_addrs, ps->n_ipv6_addrs); ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&match), action); ds_destroy(&match); free(ps->ipv6_addrs); -- 2.5.0 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
