network: Detect and add static ARP entries

[ port from runtime commit 67d3e2c5c5d11738c0c0ff46b1228909a6c81ab0 ]

Some network plugins add static arp entries in the network namespace.
Scan namespace for static entries and pass these on to the
agent to be added within the guest.

If the grpc api is not implemented by the agent due to a older running
agent, check for this and do not error out to maintain
backward compatibility.

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
Signed-off-by: Peng Tao <bergwolf@hyper.sh>
This commit is contained in:
Archana Shinde 2020-06-29 20:06:15 -07:00 committed by Peng Tao
parent 117ce4ac41
commit 520295b938
4 changed files with 138 additions and 20 deletions

View File

@ -110,6 +110,7 @@ const (
grpcUpdateInterfaceRequest = "grpc.UpdateInterfaceRequest"
grpcListInterfacesRequest = "grpc.ListInterfacesRequest"
grpcListRoutesRequest = "grpc.ListRoutesRequest"
grpcAddARPNeighborsRequest = "grpc.AddARPNeighborsRequest"
grpcOnlineCPUMemRequest = "grpc.OnlineCPUMemRequest"
grpcListProcessesRequest = "grpc.ListProcessesRequest"
grpcUpdateContainerRequest = "grpc.UpdateContainerRequest"
@ -638,6 +639,30 @@ func (k *kataAgent) updateRoutes(routes []*vcTypes.Route) ([]*vcTypes.Route, err
return nil, nil
}
func (k *kataAgent) addARPNeighbors(neighs []*vcTypes.ARPNeighbor) error {
if neighs != nil {
neighsReq := &grpc.AddARPNeighborsRequest{
Neighbors: &grpc.ARPNeighbors{
ARPNeighbors: k.convertToKataAgentNeighbors(neighs),
},
}
_, err := k.sendReq(neighsReq)
if err != nil {
if grpcStatus.Convert(err).Code() == codes.Unimplemented {
k.Logger().WithFields(logrus.Fields{
"arpneighbors-requested": fmt.Sprintf("%+v", neighs),
}).Warn("add ARP neighbors request failed due to old agent, please upgrade Kata Containers image version")
return nil
}
k.Logger().WithFields(logrus.Fields{
"arpneighbors-requested": fmt.Sprintf("%+v", neighs),
}).WithError(err).Error("add ARP neighbors request failed")
}
return err
}
return nil
}
func (k *kataAgent) listInterfaces() ([]*vcTypes.Interface, error) {
req := &grpc.ListInterfacesRequest{}
resultingInterfaces, err := k.sendReq(req)
@ -843,7 +868,7 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
//
// Setup network interfaces and routes
//
interfaces, routes, err := generateInterfacesAndRoutes(sandbox.networkNS)
interfaces, routes, neighs, err := generateVCNetworkStructures(sandbox.networkNS)
if err != nil {
return err
}
@ -853,6 +878,9 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
if _, err = k.updateRoutes(routes); err != nil {
return err
}
if err = k.addARPNeighbors(neighs); err != nil {
return err
}
storages := setupStorages(sandbox)
@ -1999,6 +2027,9 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) {
k.reqHandlers[grpcListRoutesRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
return k.client.AgentServiceClient.ListRoutes(ctx, req.(*grpc.ListRoutesRequest))
}
k.reqHandlers[grpcAddARPNeighborsRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
return k.client.AgentServiceClient.AddARPNeighbors(ctx, req.(*grpc.AddARPNeighborsRequest))
}
k.reqHandlers[grpcOnlineCPUMemRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
return k.client.AgentServiceClient.OnlineCPUMem(ctx, req.(*grpc.OnlineCPUMemRequest))
}
@ -2175,18 +2206,27 @@ func (k *kataAgent) convertToIPFamily(ipFamily aTypes.IPFamily) int {
return netlink.FAMILY_V4
}
func (k *kataAgent) convertToKataAgentIPAddress(ipAddr *vcTypes.IPAddress) (aIPAddr *aTypes.IPAddress) {
if ipAddr == nil {
return nil
}
aIPAddr = &aTypes.IPAddress{
Family: k.convertToKataAgentIPFamily(ipAddr.Family),
Address: ipAddr.Address,
Mask: ipAddr.Mask,
}
return aIPAddr
}
func (k *kataAgent) convertToKataAgentIPAddresses(ipAddrs []*vcTypes.IPAddress) (aIPAddrs []*aTypes.IPAddress) {
for _, ipAddr := range ipAddrs {
if ipAddr == nil {
continue
}
aIPAddr := &aTypes.IPAddress{
Family: k.convertToKataAgentIPFamily(ipAddr.Family),
Address: ipAddr.Address,
Mask: ipAddr.Mask,
}
aIPAddr := k.convertToKataAgentIPAddress(ipAddr)
aIPAddrs = append(aIPAddrs, aIPAddr)
}
@ -2268,6 +2308,25 @@ func (k *kataAgent) convertToKataAgentRoutes(routes []*vcTypes.Route) (aRoutes [
return aRoutes
}
func (k *kataAgent) convertToKataAgentNeighbors(neighs []*vcTypes.ARPNeighbor) (aNeighs []*aTypes.ARPNeighbor) {
for _, neigh := range neighs {
if neigh == nil {
continue
}
aNeigh := &aTypes.ARPNeighbor{
ToIPAddress: k.convertToKataAgentIPAddress(neigh.ToIPAddress),
Device: neigh.Device,
State: int32(neigh.State),
Lladdr: neigh.LLAddr,
}
aNeighs = append(aNeighs, aNeigh)
}
return aNeighs
}
func (k *kataAgent) convertToRoutes(aRoutes []*aTypes.Route) (routes []*vcTypes.Route) {
for _, aRoute := range aRoutes {
if aRoute == nil {

View File

@ -118,10 +118,11 @@ type NetlinkIface struct {
// NetworkInfo gathers all information related to a network interface.
// It can be used to store the description of the underlying network.
type NetworkInfo struct {
Iface NetlinkIface
Addrs []netlink.Addr
Routes []netlink.Route
DNS DNSInfo
Iface NetlinkIface
Addrs []netlink.Addr
Routes []netlink.Route
DNS DNSInfo
Neighbors []netlink.Neigh
}
// NetworkInterface defines a network interface.
@ -942,14 +943,15 @@ func deleteNetNS(netNSPath string) error {
return nil
}
func generateInterfacesAndRoutes(networkNS NetworkNamespace) ([]*vcTypes.Interface, []*vcTypes.Route, error) {
func generateVCNetworkStructures(networkNS NetworkNamespace) ([]*vcTypes.Interface, []*vcTypes.Route, []*vcTypes.ARPNeighbor, error) {
if networkNS.NetNsPath == "" {
return nil, nil, nil
return nil, nil, nil, nil
}
var routes []*vcTypes.Route
var ifaces []*vcTypes.Interface
var neighs []*vcTypes.ARPNeighbor
for _, endpoint := range networkNS.Endpoints {
@ -1008,10 +1010,36 @@ func generateInterfacesAndRoutes(networkNS NetworkNamespace) ([]*vcTypes.Interfa
r.Device = endpoint.Name()
r.Scope = uint32(route.Scope)
routes = append(routes, &r)
}
for _, neigh := range endpoint.Properties().Neighbors {
var n vcTypes.ARPNeighbor
// We add only static ARP entries
if neigh.State != netlink.NUD_PERMANENT {
continue
}
n.Device = endpoint.Name()
n.State = neigh.State
n.Flags = neigh.Flags
if neigh.HardwareAddr != nil {
n.LLAddr = neigh.HardwareAddr.String()
}
n.ToIPAddress = &vcTypes.IPAddress{
Family: netlink.FAMILY_V4,
Address: neigh.IP.String(),
}
if neigh.IP.To4() == nil {
n.ToIPAddress.Family = netlink.FAMILY_V6
}
neighs = append(neighs, &n)
}
}
return ifaces, routes, nil
return ifaces, routes, neighs, nil
}
func createNetworkInterfacePair(idx int, ifName string, interworkingModel NetInterworkingModel) (NetworkInterfacePair, error) {
@ -1071,13 +1099,19 @@ func networkInfoFromLink(handle *netlink.Handle, link netlink.Link) (NetworkInfo
return NetworkInfo{}, err
}
neighbors, err := handle.NeighList(link.Attrs().Index, netlink.FAMILY_ALL)
if err != nil {
return NetworkInfo{}, err
}
return NetworkInfo{
Iface: NetlinkIface{
LinkAttrs: *(link.Attrs()),
Type: link.Type(),
},
Addrs: addrs,
Routes: routes,
Addrs: addrs,
Routes: routes,
Neighbors: neighbors,
}, nil
}

View File

@ -65,13 +65,20 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
{LinkIndex: 329, Dst: nil, Src: nil, Gw: gatewayV6},
}
arpMAC, _ := net.ParseMAC("6a:92:3a:59:70:aa")
neighs := []netlink.Neigh{
{LinkIndex: 329, IP: net.IPv4(192, 168, 0, 101), State: netlink.NUD_PERMANENT, HardwareAddr: arpMAC},
}
networkInfo := NetworkInfo{
Iface: NetlinkIface{
LinkAttrs: netlink.LinkAttrs{MTU: 1500},
Type: "",
},
Addrs: addrs,
Routes: routes,
Addrs: addrs,
Routes: routes,
Neighbors: neighs,
}
ep0 := &PhysicalEndpoint{
@ -84,7 +91,7 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
nns := NetworkNamespace{NetNsPath: "foobar", NetNsCreated: true, Endpoints: endpoints}
resInterfaces, resRoutes, err := generateInterfacesAndRoutes(nns)
resInterfaces, resRoutes, resNeighs, err := generateVCNetworkStructures(nns)
//
// Build expected results:
@ -106,6 +113,15 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
{Dest: "", Gateway: "2001:db8:1::1", Device: "eth0", Source: ""},
}
expectedNeighs := []*vcTypes.ARPNeighbor{
{
Device: "eth0",
State: netlink.NUD_PERMANENT,
LLAddr: "6a:92:3a:59:70:aa",
ToIPAddress: &vcTypes.IPAddress{Address: "192.168.0.101", Family: netlink.FAMILY_V4},
},
}
for _, r := range resRoutes {
fmt.Printf("resRoute: %+v\n", r)
}
@ -115,7 +131,8 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
"Interfaces returned didn't match: got %+v, expecting %+v", resInterfaces, expectedInterfaces)
assert.True(t, reflect.DeepEqual(resRoutes, expectedRoutes),
"Routes returned didn't match: got %+v, expecting %+v", resRoutes, expectedRoutes)
assert.True(t, reflect.DeepEqual(resNeighs, expectedNeighs),
"ARP Neighbors returned didn't match: got %+v, expecting %+v", resNeighs, expectedNeighs)
}
func TestNetInterworkingModelIsValid(t *testing.T) {

View File

@ -39,3 +39,11 @@ type Route struct {
Source string
Scope uint32
}
type ARPNeighbor struct {
ToIPAddress *IPAddress
Device string
LLAddr string
State int
Flags int
}